Explorar o código

Merge remote-tracking branch 'origin/master'

zhujing hai 1 día
pai
achega
d3a8daea5f

+ 1 - 1
java/storlead-api/src/main/resources/application-dev.yml

@@ -209,7 +209,7 @@ storlead:
     remote:
       enabled: true
       scheme: http
-      host: 192.168.1.162
+      host: 192.168.1.87
       port: 10080
       context-path: /router/email
       # 也可直接写完整地址(优先于上面分项):

+ 3 - 0
java/storlead-mail/storlead-mail-api/src/main/java/com/storlead/mail/webclient/constant/MailRemoteApiConstants.java

@@ -46,6 +46,9 @@ public final class MailRemoteApiConstants {
     /** 营销邮件详情(含附件),参数:id */
     public static final String MKT_DETAIL = "/mkt/detail";
 
+    /** 通过id查询邮件列表,参数:List<Long> ids */
+    public static final String MKT_LIST_BY_IDS = "/mkt/list_by_ids";
+
     /** 营销邮件详情(对齐 CRM get_mail_detial),参数:mailId */
     public static final String MKT_GET_MAIL_DETAIL = "/mkt/get_mail_detial";
 

+ 4 - 0
java/storlead-mail/storlead-mail-api/src/main/java/com/storlead/mail/webclient/support/MailRemoteHttpSupport.java

@@ -99,6 +99,10 @@ public class MailRemoteHttpSupport {
         return token;
     }
 
+    /**
+     * POST JSON。body 会原样序列化:List 会变成 {@code [1,2,3]},只适合 B 端 {@code @RequestBody}。
+     * B 端若是 {@code @RequestParam("ids") List<Long>},请用 {@link #postForm(String, Object)} + {@link #formOf}。
+     */
     public Result<?> postJson(String path, Object body) {
         try {
             return mailWebClient.post()

+ 16 - 0
java/storlead-mail/storlead-mail-core/src/main/java/com/storlead/mail/pojo/entity/MktMailStatusEntity.java

@@ -94,4 +94,20 @@ public class MktMailStatusEntity extends SysBaseField {
     @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @TableField("synced_at")
     private Date syncedAt;
+
+    @ApiModelProperty(value = "全部回复邮件id,逗号隔开")
+    @TableField("reply_email_ids")
+    private String replyEmailIds;
+
+    @ApiModelProperty(value = "发件箱id")
+    @TableField("outbox_id")
+    private Integer outboxId;
+
+    @ApiModelProperty(value = "发件箱")
+    @TableField("outbox")
+    private String outbox;
+
+    @ApiModelProperty(value = "是否拒收(0没有、1拒收)")
+    @TableField("has_refuse")
+    private Integer hasRefuse;
 }

+ 75 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/client/MarketEmailsClient.java

@@ -0,0 +1,75 @@
+package com.storlead.trade.client;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.storlead.framework.common.result.Result;
+import com.storlead.framework.core.tenant.TenantConstants;
+import com.storlead.mail.webclient.config.MailRemoteProperties;
+import com.storlead.mail.webclient.constant.MailRemoteApiConstants;
+import com.storlead.mail.webclient.support.MailRemoteHttpSupport;
+import lombok.RequiredArgsConstructor;
+import org.springframework.util.StringUtils;
+import org.springframework.web.reactive.function.client.WebClient;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * CRM 邮箱账户远程客户端,对齐 B 服务 {@code /mkt/**}。
+ */
+@RequiredArgsConstructor
+public class MarketEmailsClient {
+
+    /** 默认连 application-dev.yml 里配的那台邮件服务;要换机器就用 main 的 args[0] 覆盖 */
+    private static final String DEFAULT_BASE_URL = "http://192.168.1.87:10080/router/email";
+
+    private final MailRemoteHttpSupport http;
+
+    public Result<?> emailList(List<Long> ids) {
+        // B 服务是 @RequestParam("ids") List<Long>,必须按 form 重复 key:ids=2&ids=3。
+        // 不能 postJson 直接传 List:body 会变成 [2,3],B 端当成字符串 "[2, 3]" 再按逗号拆,
+        // 得到 "[2" 和 " 3]",转不成 Long,表现为 list size 正确但元素全是 null。
+        // 也不能 postForm(path, ids):toForm 会对 List 做 convertValue(..., Map) 抛异常。
+        return http.postForm(MailRemoteApiConstants.MKT_LIST_BY_IDS, http.formOf("ids", ids));
+    }
+
+    /**
+     * 本地直连调试入口:不启动 Spring 容器,手工搭一个 MailRemoteHttpSupport 出来。
+     * <p>
+     * 脱离 Web 容器运行时没有登录态和请求上下文,必须关掉 token / 租户透传,
+     * 否则 authHeaders() 会去调 LoginUserUtil / RequestContextHolder,取不到值甚至报错。
+     * 需要鉴权时改用 args 把 token / 租户塞进默认请求头。
+     *
+     * <pre>
+     * 默认连 dev:直接 Run main
+     * 换地址:args[0] = http://127.0.0.1:18090/router/email
+     * 带 token:args[1] = eyJhbGciOi...(B 服务 AuthFilter 用的 header 名由 tokenHeader 决定,默认 token)
+     * 带租户:args[2] = 1234567890123456789(写入 X-Tenant-Id)
+     * </pre>
+     */
+    public static void main(String[] args) {
+        String baseUrl = args.length > 0 ? args[0] : DEFAULT_BASE_URL;
+        String token = args.length > 1 ? args[1] : null;
+        String tenantId = args.length > 2 ? args[2] : null;
+
+        MailRemoteProperties properties = new MailRemoteProperties();
+        properties.setBaseUrl(baseUrl);
+        properties.setForwardToken(false);
+        properties.setForwardTenant(false);
+
+        String tokenHeader = properties.getTokenHeader();
+        WebClient.Builder builder = WebClient.builder()
+                .baseUrl(properties.resolveBaseUrl());
+        // 这里绕开 authHeaders():它依赖 LoginUserUtil / RequestContextHolder,容器外取不到
+        if (StringUtils.hasText(token)) {
+            builder.defaultRequest(req -> req.header(tokenHeader, token));
+        }
+        if (StringUtils.hasText(tenantId)) {
+            builder.defaultRequest(req -> req.header(TenantConstants.HTTP_HEADER_TENANT_ID, tenantId));
+        }
+
+        MailRemoteHttpSupport http = new MailRemoteHttpSupport(
+                builder.build(), properties, new ObjectMapper());
+
+        System.out.println(new MarketEmailsClient(http).emailList(Arrays.asList(2L, 3L)));
+    }
+}

+ 25 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/config/TradeMailRemoteClientConfig.java

@@ -0,0 +1,25 @@
+package com.storlead.trade.config;
+
+import com.storlead.mail.webclient.support.MailRemoteHttpSupport;
+import com.storlead.trade.client.MarketEmailsClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * trade 模块用到的邮件远程客户端装配。
+ * <p>
+ * {@link MarketEmailsClient} 本身不带 {@code @Component},和 storlead-mail-api 里
+ * {@code CrmMailRemoteClient} / {@code MktMailRemoteClient} 等保持一致的写法——
+ * 那些 client 也都是在 {@code MailWebClientAutoConfiguration} 里用 {@code @Bean} 注册的。
+ * <p>
+ * 构造参数是邮件模块的 {@link MailRemoteHttpSupport},由 storlead-mail-api 的
+ * 自动装配提供(受 {@code storlead.mail.remote.enabled} 与 base-url / host 配置约束)。
+ */
+@Configuration
+public class TradeMailRemoteClientConfig {
+
+    @Bean
+    public MarketEmailsClient marketEmailsClient(MailRemoteHttpSupport mailRemoteHttpSupport) {
+        return new MarketEmailsClient(mailRemoteHttpSupport);
+    }
+}

+ 15 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/controller/MarketEmailsController.java

@@ -1,5 +1,8 @@
 package com.storlead.trade.controller;
 
+import com.storlead.framework.common.dto.page.PageDTO;
+import com.storlead.mail.webclient.client.CrmAccountRemoteClient;
+import com.storlead.trade.client.MarketEmailsClient;
 import com.storlead.trade.dto.MarketEmailsDTO;
 import com.storlead.trade.entity.MarketEmailsEntity;
 import com.storlead.trade.service.MarketEmailsService;
@@ -14,6 +17,7 @@ import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.util.List;
@@ -28,6 +32,9 @@ public class MarketEmailsController {
     @Resource
     private MarketEmailsService marketEmailsService;
 
+    @Resource
+    private MarketEmailsClient marketEmailsClient;
+
     @PostMapping("/list")
     @ApiOperation("营销: 营销邮件列表")
     public Result<Object> list(@RequestBody MarketEmailsDTO marketEmailsDTO) {
@@ -142,4 +149,12 @@ public class MarketEmailsController {
     public Result<Object> managementPage(@RequestBody MarketEmailsDTO marketEmailsDTO) {
         return marketEmailsService.getManagementPage(marketEmailsDTO);
     }
+
+
+
+    @PostMapping("/test")
+    @ApiOperation("获取邮件信息(form 传 ids,多个用逗号分隔或重复 key:ids=1,2 或 ids=1&ids=2)")
+    public Result<?> emailList(@RequestParam("ids") List<Long> ids) {
+        return marketEmailsClient.emailList(ids);
+    }
 }

+ 22 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/MarketEmailsStatusSyncServiceImpl.java

@@ -13,6 +13,7 @@ import com.storlead.trade.service.MarketEmailsStatusSyncService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
 
 import javax.annotation.Resource;
 import java.util.ArrayList;
@@ -161,6 +162,27 @@ public class MarketEmailsStatusSyncServiceImpl implements MarketEmailsStatusSync
             update.set(MarketEmailsEntity::getFirstReplyTheme, change.getFirstReplyTheme());
             changed = true;
         }
+        // 全部回复邮件 id(逗号隔开):邮件侧是全量列表,有变化则覆盖
+        if (StringUtils.hasText(change.getReplyEmailIds())
+                && !change.getReplyEmailIds().equals(existing.getReplyEmailIds())) {
+            update.set(MarketEmailsEntity::getReplyEmailIds, change.getReplyEmailIds());
+            changed = true;
+        }
+        // 发件箱:空才补
+        if (existing.getOutboxId() == null && change.getOutboxId() != null) {
+            update.set(MarketEmailsEntity::getOutboxId, change.getOutboxId());
+            changed = true;
+        }
+        if (!StringUtils.hasText(existing.getOutbox()) && StringUtils.hasText(change.getOutbox())) {
+            update.set(MarketEmailsEntity::getOutbox, change.getOutbox());
+            changed = true;
+        }
+        // 拒收:只升 1,不回退
+        if (Integer.valueOf(1).equals(change.getHasRefuse())
+                && !Integer.valueOf(1).equals(existing.getHasRefuse())) {
+            update.set(MarketEmailsEntity::getHasRefuse, 1);
+            changed = true;
+        }
         if (!changed) {
             return ApplyResult.MATCHED_NO_CHANGE;
         }

+ 1 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/task/MarketEmailsSendSyncTask.java

@@ -1,5 +1,6 @@
 package com.storlead.trade.task;
 
+import com.storlead.mail.webclient.constant.MailRemoteApiConstants;
 import com.storlead.trade.service.MarketEmailsService;
 import com.storlead.trade.service.MarketEmailsStatusSyncService;
 import lombok.extern.slf4j.Slf4j;