Przeglądaj źródła

chore: merge master

周玉环 4 dni temu
rodzic
commit
da888803f8
44 zmienionych plików z 1399 dodań i 105 usunięć
  1. 1 1
      xinkeaboard-server/b2b2c-core/src/main/java/com/slodon/b2b2c/core/config/DomainUrlUtil.java
  2. 108 0
      xinkeaboard-server/b2b2c-core/src/main/java/com/slodon/b2b2c/core/util/HttpClientUtil.java
  3. 1 1
      xinkeaboard-server/b2b2c-core/src/main/resources/i18n_en.properties
  4. 3 0
      xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/goods/dto/GoodsRankListDTO.java
  5. 57 0
      xinkeaboard-server/b2b2c-investment/pom.xml
  6. 27 0
      xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/bo/CompetitorBO.java
  7. 23 0
      xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/bo/MonthlySearchesBO.java
  8. 96 0
      xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/bo/RankBO.java
  9. 29 0
      xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/bo/RecommendationBO.java
  10. 22 0
      xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/bo/RelatedInfoBO.java
  11. 22 0
      xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/bo/TrafficBO.java
  12. 24 0
      xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/dto/RivalDTO.java
  13. 22 0
      xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/dto/SearchVolumeDTO.java
  14. 29 0
      xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/vo/KeyWordPartVO.java
  15. 20 0
      xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/vo/RivalPartVO.java
  16. 20 0
      xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/vo/SuggestionVO.java
  17. 27 0
      xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/config/AnalysisConfig.java
  18. 55 0
      xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/constant/AnalysisConst.java
  19. 118 0
      xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/controller/AnalysisController.java
  20. 463 0
      xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/model/AnalysisModel.java
  21. 6 0
      xinkeaboard-server/b2b2c-web/pom.xml
  22. 3 2
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/goods/seller/GoodsCategorySellerController.java
  23. 4 3
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/member/admin/AdminEnquiryController.java
  24. 1 1
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/member/front/advich/MemberEmailActiveController.java
  25. 3 3
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/member/seller/advich/SellerEnquiryController.java
  26. 5 0
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/msg/front/VerifyController.java
  27. 2 2
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/sso/front/FrontAuthController.java
  28. 6 6
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/system/admin/SearchInitController.java
  29. 4 0
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/dao/read/goods/GoodsExtendReadMapper.java
  30. 18 3
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/dao/read/member/MemberEnquiryReadMapper.java
  31. 1 1
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/interceptor/BearerTokenConfiguration.java
  32. 15 5
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/job/GoodsJob.java
  33. 85 64
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/model/goods/ESGoodsModel.java
  34. 3 0
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/model/goods/GoodsExtendModel.java
  35. 24 8
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/model/member/advich/MemberEnquiryModel.java
  36. 2 2
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/model/member/advich/MemberRegisterActiveModel.java
  37. 1 1
      xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/model/seller/SellerStoreCompanyShowModel.java
  38. 13 0
      xinkeaboard-server/b2b2c-web/src/main/resources/application-dev.yml
  39. 1 0
      xinkeaboard-server/b2b2c-web/src/main/resources/application.yml
  40. 4 1
      xinkeaboard-server/b2b2c-web/src/main/resources/mapper/read/goods/GoodsBindRankReadMapper.xml
  41. 5 0
      xinkeaboard-server/b2b2c-web/src/main/resources/mapper/read/goods/GoodsExtendReadMapper.xml
  42. 12 0
      xinkeaboard-server/b2b2c-web/src/main/resources/mapper/read/member/MemberEnquiryReadMapper.xml
  43. 13 1
      xinkeaboard-server/doc/DDL/update.sql
  44. 1 0
      xinkeaboard-server/pom.xml

+ 1 - 1
xinkeaboard-server/b2b2c-core/src/main/java/com/slodon/b2b2c/core/config/DomainUrlUtil.java

@@ -122,7 +122,7 @@ public class DomainUrlUtil {
     /**
      * 发送短信类型,1-腾讯云发送,2-云片发送,3-阿里云发送
      */
-    public static final Integer SEND_SMS_TYPE = 1;
+    public static final Integer SEND_SMS_TYPE = 3;
 
     /**
      * 数据清洗模式,1==清除模式,2==转义模式

+ 108 - 0
xinkeaboard-server/b2b2c-core/src/main/java/com/slodon/b2b2c/core/util/HttpClientUtil.java

@@ -94,6 +94,114 @@ public class HttpClientUtil {
         return result;
     }
 
+
+    /**
+     * 发送HTTP POST请求,使用String类型作为请求体参数
+     * @param url 请求URL
+     * @param params 请求体参数(通常为JSON字符串)
+     * @param headers 请求头信息
+     * @return 响应结果字符串
+     * @throws Exception 可能抛出的异常
+     */
+    public static String httpPost(String url, String params, HashMap<String, String> headers) throws Exception {
+        String result = "";
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        HttpPost httpPost = new HttpPost(url);
+
+        // 设置最大请求和传输超时时间
+        RequestConfig requestConfig = RequestConfig.custom()
+                .setSocketTimeout(50000)
+                .setConnectTimeout(50000)
+                .build();
+        httpPost.setConfig(requestConfig);
+
+        // 设置请求头
+        if (headers != null && !headers.isEmpty()) {
+            for (String key : headers.keySet()) {
+                httpPost.addHeader(key, headers.get(key));
+            }
+        }
+
+        // 设置请求体参数
+        if (params != null && !params.isEmpty()) {
+            // 使用StringEntity直接设置字符串作为请求体
+            StringEntity stringEntity = new StringEntity(params, StandardCharsets.UTF_8);
+            httpPost.setEntity(stringEntity);
+        }
+
+        CloseableHttpResponse response = httpClient.execute(httpPost);
+
+        try {
+            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+                HttpEntity entity = response.getEntity();
+                result = EntityUtils.toString(entity, StandardCharsets.UTF_8);
+                EntityUtils.consume(entity);
+            } else {
+                throw new Exception(response.getStatusLine().toString());
+            }
+        } finally {
+            response.close();
+            httpClient.close();
+        }
+        return result;
+    }
+
+
+
+    /**
+     * http POST 请求,支持自定义请求头
+     *
+     * @param url     请求URL
+     * @param params  请求参数
+     * @param headers 请求头信息
+     * @return 响应结果字符串
+     * @throws Exception 异常信息
+     */
+    public static String httpPost(String url, HashMap<String, Object> params, HashMap<String, String> headers) throws Exception {
+        String result = "";
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        HttpPost httpPost = new HttpPost(url);
+
+        // 设置最大请求和传输超时时间
+        RequestConfig requestConfig = RequestConfig.custom()
+                .setSocketTimeout(5000)
+                .setConnectTimeout(5000)
+                .build();
+        httpPost.setConfig(requestConfig);
+
+        // 设置请求头
+        if (headers != null && !headers.isEmpty()) {
+            for (String key : headers.keySet()) {
+                httpPost.addHeader(key, headers.get(key));
+            }
+        }
+
+        // 拼接请求参数
+        java.util.List<NameValuePair> nvps = new ArrayList<>();
+        if (params != null && !params.isEmpty()) {
+            for (String key : params.keySet()) {
+                nvps.add(new BasicNameValuePair(key, params.get(key).toString()));
+            }
+        }
+        httpPost.setEntity(new UrlEncodedFormEntity(nvps, StandardCharsets.UTF_8));
+
+        CloseableHttpResponse response = httpClient.execute(httpPost);
+
+        try {
+            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+                HttpEntity entity = response.getEntity();
+                result = EntityUtils.toString(entity, StandardCharsets.UTF_8);
+                EntityUtils.consume(entity);
+            } else {
+                throw new Exception(response.getStatusLine().toString());
+            }
+        } finally {
+            response.close();
+            httpClient.close(); // 补充关闭httpClient,释放资源
+        }
+        return result;
+    }
+
     /**
      * http POST 请求
      *

+ 1 - 1
xinkeaboard-server/b2b2c-core/src/main/resources/i18n_en.properties

@@ -1809,7 +1809,7 @@ admin账号不可删除=admin account can not be deleted
 更新直播和短视频设置表失败,请重试=Live updates and short video settings table failed, please try again
 退出成功=exit successfully
 用户名或密码错误=wrong user name or password
-会员账号或密码错误=wrong member email or password
+会员账号或密码错误=wrong member account or password
 系统开小差了=System deserted
 账号已被冻结=Account has been frozen
 账号不可用=Account unavailable

+ 3 - 0
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/goods/dto/GoodsRankListDTO.java

@@ -30,4 +30,7 @@ public class GoodsRankListDTO {
 
     @ApiModelProperty("创建时间")
     private Date createTime;
+
+    @ApiModelProperty("商品Id")
+    private Long goodsId;
 }

+ 57 - 0
xinkeaboard-server/b2b2c-investment/pom.xml

@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>b2b2c</artifactId>
+        <groupId>com.slodon</groupId>
+        <version>3.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>b2b2c-investment</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.slodon</groupId>
+            <artifactId>b2b2c-entity</artifactId>
+            <version>3.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.slodon</groupId>
+            <artifactId>b2b2c-core</artifactId>
+            <version>3.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.12.0</version>
+        </dependency>
+
+        <!--   knife4j     -->
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-spring-boot-starter</artifactId>
+            <version>2.0.4</version>
+        </dependency>
+
+        <!-- Lombok 依赖 -->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.2</version>
+            <optional>true</optional>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 27 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/bo/CompetitorBO.java

@@ -0,0 +1,27 @@
+package com.slodon.b2b2c.investment.bean.bo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author sunshihao
+ * @version 1.0
+ * @description: 竞品网站信息
+ * @date 2025/8/7 16:20
+ */
+@Data
+public class CompetitorBO {
+    @ApiModelProperty("竞品网站")
+    private String website;
+
+    @ApiModelProperty("折线图对象")
+    private List<TrafficBO> trafficBOList;
+
+    @ApiModelProperty("排名表格")
+    private List<RankBO> rankBOList;
+
+    @ApiModelProperty("推荐表格")
+    private List<RecommendationBO> recommendationBOList;
+}

+ 23 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/bo/MonthlySearchesBO.java

@@ -0,0 +1,23 @@
+package com.slodon.b2b2c.investment.bean.bo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author sunshihao
+ * @version 1.0
+ * @description: TODO
+ * @date 2025/8/7 11:19
+ */
+@Data
+public class MonthlySearchesBO {
+    @ApiModelProperty("年份")
+    private  Integer year;
+
+    @ApiModelProperty("搜索量")
+    private  Long search_volume;
+
+    @ApiModelProperty("月份")
+    private  Integer month;
+
+}

+ 96 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/bo/RankBO.java

@@ -0,0 +1,96 @@
+package com.slodon.b2b2c.investment.bean.bo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author sunshihao
+ * @version 1.0
+ * @description: TODO
+ * @date 2025/8/6 15:34
+ */
+@Data
+public class RankBO {
+    @ApiModelProperty("关键词")
+    private  String keyword;
+
+    @ApiModelProperty("月平均搜索量")
+    private  Long searchVolume;
+
+    @ApiModelProperty("月度变化")
+    private  Long monthly;
+
+    @ApiModelProperty("季度变化")
+    private  Long quarterly;
+
+    @ApiModelProperty("年度变化")
+    private  Long yearly;
+
+    @ApiModelProperty("难度")
+    private  Integer dp;
+
+    @ApiModelProperty("每次点击费用")
+    private  Double cpc;
+
+    public static RankBOBuilder builder() {
+        return new RankBOBuilder();
+    }
+
+    public static class RankBOBuilder {
+        private String keyword;
+        private Long searchVolume;
+        private Long monthly;
+        private Long quarterly;
+        private Long yearly;
+        private Integer dp;
+        private Double cpc;
+
+        public RankBOBuilder keyword(String keyword) {
+            this.keyword = keyword;
+            return this;
+        }
+
+        public RankBOBuilder searchVolume(Long searchVolume) {
+            this.searchVolume = searchVolume;
+            return this;
+        }
+
+        public RankBOBuilder monthly(Long monthly) {
+            this.monthly = monthly;
+            return this;
+        }
+
+        public RankBOBuilder quarterly(Long quarterly) {
+            this.quarterly = quarterly;
+            return this;
+        }
+
+        public RankBOBuilder yearly(Long yearly) {
+            this.yearly = yearly;
+            return this;
+        }
+
+        public RankBOBuilder dp(Integer dp) {
+            this.dp = dp;
+            return this;
+        }
+
+        public RankBOBuilder cpc(Double cpc) {
+            this.cpc = cpc;
+            return this;
+        }
+
+        public RankBO build() {
+            RankBO rankBO = new RankBO();
+            rankBO.setKeyword(this.keyword);
+            rankBO.setSearchVolume(this.searchVolume);
+            rankBO.setMonthly(this.monthly);
+            rankBO.setQuarterly(this.quarterly);
+            rankBO.setYearly(this.yearly);
+            rankBO.setDp(this.dp);
+            rankBO.setCpc(this.cpc);
+            return rankBO;
+        }
+    }
+
+}

+ 29 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/bo/RecommendationBO.java

@@ -0,0 +1,29 @@
+package com.slodon.b2b2c.investment.bean.bo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author sunshihao
+ * @version 1.0
+ * @description: 推荐投放信息
+ * @date 2025/8/6 15:16
+ */
+@Data
+public class RecommendationBO {
+    /**
+     * 关键词
+     */
+    @ApiModelProperty("关键词")
+    private String keywords;
+    /**
+     * 搜索量
+     */
+    @ApiModelProperty("搜索量")
+    private Long searchVolume;
+    /**
+     * 价格
+     */
+    @ApiModelProperty("价格")
+    private Double price;
+}

+ 22 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/bo/RelatedInfoBO.java

@@ -0,0 +1,22 @@
+package com.slodon.b2b2c.investment.bean.bo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author sunshihao
+ * @version 1.0
+ * @description: 相关关键词信息
+ * @date 2025/8/6 15:26
+ */
+@Data
+public class RelatedInfoBO {
+    @ApiModelProperty("搜索量")
+    private Long searchVolume;
+
+    @ApiModelProperty("关键词难度")
+    private Integer competition;
+
+    @ApiModelProperty("关键词")
+    private String keyword;
+}

+ 22 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/bo/TrafficBO.java

@@ -0,0 +1,22 @@
+package com.slodon.b2b2c.investment.bean.bo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author sunshihao
+ * @version 1.0
+ * @description: TODO
+ * @date 2025/8/6 15:31
+ */
+@Data
+public class TrafficBO {
+    @ApiModelProperty("x轴")
+    private int x_axis;
+
+    @ApiModelProperty("自然流量")
+    private Long organic;
+
+    @ApiModelProperty("付费流量")
+    private Long paid;
+}

+ 24 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/dto/RivalDTO.java

@@ -0,0 +1,24 @@
+package com.slodon.b2b2c.investment.bean.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author sunshihao
+ * @version 1.0
+ * @description: 入参
+ * @date 2025/8/5 13:22
+ */
+@Data
+public class RivalDTO {
+    @ApiModelProperty("目标区域")
+    @NotBlank(message = "目标区域不能为空")
+    private String locationName;
+
+    @ApiModelProperty("竞品网站(多个逗号隔开)")
+    @NotBlank(message = "竞品网站不能为空")
+    private String competitorWebsite;
+
+}

+ 22 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/dto/SearchVolumeDTO.java

@@ -0,0 +1,22 @@
+package com.slodon.b2b2c.investment.bean.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author sunshihao
+ * @version 1.0
+ * @description: TODO
+ * @date 2025/8/7 11:46
+ */
+@Data
+public class SearchVolumeDTO {
+    @ApiModelProperty("产品名称")
+    @NotBlank(message = "关键词不能为空")
+    private String productName;
+    @ApiModelProperty("目标区域")
+    @NotBlank(message = "目标区域不能为空")
+    private String locationName;
+}

+ 29 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/vo/KeyWordPartVO.java

@@ -0,0 +1,29 @@
+package com.slodon.b2b2c.investment.bean.vo;
+
+import com.slodon.b2b2c.investment.bean.bo.MonthlySearchesBO;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author sunshihao
+ * @version 1.0
+ * @description: 关键词部分
+ * @date 2025/8/6 15:21
+ */
+@Data
+public class KeyWordPartVO {
+    @ApiModelProperty("互联网关键词")
+    private List<String> keywords;
+
+    @ApiModelProperty("最近月搜索量")
+    private MonthlySearchesBO monthlySearchesBO;
+
+    @ApiModelProperty("关键词难度")
+    private Integer competition;
+
+    @ApiModelProperty("英文表达")
+    private String keywordEn;
+
+}

+ 20 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/vo/RivalPartVO.java

@@ -0,0 +1,20 @@
+package com.slodon.b2b2c.investment.bean.vo;
+
+import com.slodon.b2b2c.investment.bean.bo.CompetitorBO;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author sunshihao
+ * @version 1.0
+ * @description: 竞品部分
+ * @date 2025/8/6 15:29
+ */
+@Data
+public class RivalPartVO {
+    @ApiModelProperty("竞品网站信息")
+    private List<CompetitorBO> competitorBOS;
+
+}

+ 20 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/bean/vo/SuggestionVO.java

@@ -0,0 +1,20 @@
+package com.slodon.b2b2c.investment.bean.vo;
+
+import com.slodon.b2b2c.investment.bean.bo.RelatedInfoBO;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author sunshihao
+ * @version 1.0
+ * @description: 相关关键词搜索量及难度
+ * @date 2025/8/7 14:44
+ */
+@Data
+public class SuggestionVO {
+    @ApiModelProperty("相关关键词搜索量及难度")
+    private List<RelatedInfoBO> relatedInfoBOList;
+
+}

+ 27 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/config/AnalysisConfig.java

@@ -0,0 +1,27 @@
+package com.slodon.b2b2c.investment.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author sunshihao
+ * @version 1.0
+ * @description: 配置类
+ * @date 2025/8/5 14:20
+ */
+@Component
+@ConfigurationProperties(prefix = "analysis")
+@Data
+public class AnalysisConfig {
+    private String translateAddress;
+    private String loginUser;
+    private String password;
+    private String searchVolume;
+    private String keywordsForSite;
+    private String KeywordForSuggestions;
+    private String rankedKeywords;
+    private String historicalTraffic;
+    private String modelName;
+
+}

+ 55 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/constant/AnalysisConst.java

@@ -0,0 +1,55 @@
+package com.slodon.b2b2c.investment.constant;
+
+/**
+ * @author sunshihao
+ * @version 1.0
+ * @description: TODO
+ * @date 2025/8/5 15:33
+ */
+public class AnalysisConst {
+    /**
+     * 默认固定线程数
+     */
+    public static final int DEFAULT_RUN_THREAD_NUM = 2;
+
+    public static final int NUM_ZERO = 0;
+    public static final int NUM_ONE = 1;
+    public static final int NUM_TWO = 2;
+    public static final int NUM_THREE = 3;
+    public static final int NUM_FOUR = 4;
+    public static final long NUM_TEN = 10;
+    public static final int NUM_FIFTY = 50;
+    public static final int NUM_ONE_HUNDRED = 100;
+    public static final int NEGATIVE_ONE = -1;
+    /**
+     * 线程池存活时间
+     */
+    public static final long KEEP_ALIVE_TIME = 5000L;
+    /**
+     * 等待队列大小
+     */
+    public static final int WORK_QUEUE = 2;
+    public static final Double ONE_HUNDRED_DOUBLE = 100.0;
+    public static final String CONTENT_TYPE = "Content-Type";
+    public static final String APPLICATION_JSON = "application/json";
+    public static final String TEXT = "text";
+    public static final String MODEL_NAME = "model_name";
+    public static final String AUTHORIZATION = "Authorization";
+    public static final String KEYWORDS = "keywords";
+    public static final String LANGUAGE_NAME = "language_name";
+    public static final String LOCATION_NAME = "location_name";
+    public static final String ENGLISH = "English";
+    public static final String LIMIT = "limit";
+    public static final String TARGET = "target";
+    public static final String HTTPS = "https://";
+    public static final String HTTP = "http://";
+    public static final String WWW = "www.";
+    public static final String COM = ".com";
+    public static final String TARGETS = "targets";
+    public static final String KEYWORD = "keyword";
+    public static final String CHINESE = "chinese";
+    public static final String LAST_PART_MARKER = "```\n" +
+            "\n" +
+            "## 参考资料";
+    public static final String FIRST_MARKER = "## 4. 引用";
+}

+ 118 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/controller/AnalysisController.java

@@ -0,0 +1,118 @@
+package com.slodon.b2b2c.investment.controller;
+
+import com.slodon.b2b2c.core.response.JsonResult;
+import com.slodon.b2b2c.core.response.SldResponse;
+
+import com.slodon.b2b2c.investment.bean.dto.RivalDTO;
+import com.slodon.b2b2c.investment.bean.dto.SearchVolumeDTO;
+import com.slodon.b2b2c.investment.bean.vo.KeyWordPartVO;
+import com.slodon.b2b2c.investment.bean.vo.RivalPartVO;
+import com.slodon.b2b2c.investment.bean.vo.SuggestionVO;
+import com.slodon.b2b2c.investment.model.AnalysisModel;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.List;
+
+
+/**
+ * @author sunshihao
+ * @version 1.0
+ * @description: 定量分析控制层
+ * @date 2025/8/5 10:56
+ */
+
+@Api(tags = "招商分析控制")
+@RestController
+@RequestMapping("/analysis")
+@Slf4j
+public class AnalysisController {
+    @Resource
+    private AnalysisModel analysisModel;
+
+    /***
+     * @description: 接口1 返回页面左上 关键词搜索量 关键词难度
+     * @param:
+     * @param dto
+     * @author sunshihao
+     * @date: 2025/8/7 13:46
+     */
+    @PostMapping("/keyword")
+    public JsonResult<KeyWordPartVO> searchVolume(@RequestBody SearchVolumeDTO dto) {
+        HashMap<String,String> headers = analysisModel.getCredential();
+        KeyWordPartVO result;
+        try {
+        List<String> keyword = analysisModel.translateProduct(dto.getProductName());
+        result = analysisModel.searchVolume(headers, keyword.get(0), dto.getLocationName());
+        result.setKeywordEn(keyword.get(0));
+        result.setKeywords(keyword);
+        }catch (Exception e) {
+                log.error(e.getMessage(),e);
+            return SldResponse.fail("Analysis failed: " + e.getMessage());
+        }
+        return SldResponse.success(result);
+    }
+
+    @PostMapping("/suggestions")
+    public JsonResult<SuggestionVO> suggestions(@RequestBody SearchVolumeDTO dto) {
+        HashMap<String,String> headers = analysisModel.getCredential();
+        SuggestionVO result;
+        try {
+            List<String> keyword = analysisModel.translateProduct(dto.getProductName());
+            result = analysisModel.KeywordForSuggestions(headers, keyword.get(0), dto.getLocationName());
+        }catch (Exception e) {
+            log.error(e.getMessage(),e);
+            return SldResponse.fail("Analysis failed: " + e.getMessage());
+        }
+        return SldResponse.success(result);
+    }
+
+
+
+    /***
+     * @description: 竞品网站信息
+     * @param dto
+     * @return: com.slodon.b2b2c.core.response.JsonResult<com.slodon.b2b2c.investment.bean.vo.RivalPartVO>
+     * @author sunshihao
+     * @date: 2025/8/8 13:23
+     */
+    @PostMapping("/rival")
+    public JsonResult<RivalPartVO> rival(@RequestBody RivalDTO dto) {
+        HashMap<String,String> headers = analysisModel.getCredential();
+        RivalPartVO result;
+        try {
+            result = analysisModel.rival(headers, dto);
+        }catch (Exception e) {
+            log.error(e.getMessage(),e);
+            return SldResponse.fail("Analysis failed: " + e.getMessage());
+        }
+        return SldResponse.success(result);
+    }
+
+
+
+    /***
+     * @description: 定性分析
+     * @param:
+     * @param keyword  关键词
+     * @return: com.slodon.b2b2c.core.response.JsonResult<java.lang.String>
+     * @author sunshihao
+     * @date: 2025/8/8 13:30
+     */
+    @GetMapping("/qualitative")
+    public JsonResult<String> qualitative(@RequestParam String keyword) {
+        String result;
+        try {
+            result = analysisModel.qualitative(keyword);
+        }catch (Exception e) {
+            log.error(e.getMessage(),e);
+            return SldResponse.fail("Analysis failed: " + e.getMessage());
+        }
+        return SldResponse.success(result);
+    }
+
+
+}

+ 463 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/model/AnalysisModel.java

@@ -0,0 +1,463 @@
+package com.slodon.b2b2c.investment.model;
+
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.slodon.b2b2c.core.util.HttpClientUtil;
+import com.slodon.b2b2c.investment.bean.bo.*;
+import com.slodon.b2b2c.investment.bean.dto.RivalDTO;
+import com.slodon.b2b2c.investment.bean.vo.KeyWordPartVO;
+import com.slodon.b2b2c.investment.bean.vo.RivalPartVO;
+import com.slodon.b2b2c.investment.bean.vo.SuggestionVO;
+import com.slodon.b2b2c.investment.config.AnalysisConfig;
+import com.slodon.b2b2c.investment.constant.AnalysisConst;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.nio.charset.StandardCharsets;
+import javax.annotation.Resource;
+import java.util.concurrent.*;
+
+
+/**
+ * @author sunshihao
+ * @version 1.0
+ * @description: 定量分析模型
+ * @date 2025/8/5 11:24
+ */
+@Component
+@Slf4j
+public class AnalysisModel {
+
+
+    @Resource
+    private AnalysisConfig analysisConfig;
+
+
+
+/***
+ * @description:翻译产品名称
+ * @param originalText 各语言名称
+ * @return: java.lang.String
+ * @author sunshihao
+ * @date: 2025/8/5 13:52
+ */
+public List<String> translateProduct(String originalText) throws Exception {
+    HashMap<String, String> headers = new HashMap<>();
+    headers.put(AnalysisConst.CONTENT_TYPE, AnalysisConst.APPLICATION_JSON);
+    JSONObject param = new JSONObject();
+    param.set(AnalysisConst.TEXT, originalText);
+    param.set(AnalysisConst.MODEL_NAME, analysisConfig.getModelName());
+    String result;
+    try {
+        result = HttpClientUtil.httpPost(analysisConfig.getTranslateAddress() + "/api/translate", param.toString(), headers);
+    } catch (Exception e) {
+        log.error(e.getMessage(), "产品翻译接口出错");
+        throw new Exception("产品翻译接口出错", e);
+    }
+    JSONObject jsonObject = JSONUtil.parseObj(result);
+    String text = jsonObject.getByPath("translated_text", String.class);
+    if (StringUtils.isEmpty(text)) {
+        throw new Exception("翻译结果为空");
+    }
+    int start = text.indexOf("[");
+    int end = text.lastIndexOf("]") + AnalysisConst.NUM_ONE;
+    String jsonString = "";
+    if (start != AnalysisConst.NEGATIVE_ONE && end != AnalysisConst.NEGATIVE_ONE && start < end) {
+        jsonString = text.substring(start, end);
+    } else {
+        throw new Exception("未找到翻译结果");
+    }
+    return JSONUtil.parseArray(jsonString).toList(String.class);
+}
+
+
+public HashMap<String,String> getCredential(){
+    String credentials = analysisConfig.getLoginUser() + ":" + analysisConfig.getPassword();
+    // 进行Base64编码
+    String base64Creds = Base64.getEncoder()
+            .encodeToString(credentials.getBytes(StandardCharsets.UTF_8));
+    // 创建请求头Map
+    HashMap<String, String> headers = new HashMap<>();
+    headers.put(AnalysisConst.CONTENT_TYPE, AnalysisConst.APPLICATION_JSON);
+    headers.put(AnalysisConst.AUTHORIZATION, "Basic " + base64Creds);
+    return headers;
+}
+
+
+private ThreadPoolExecutor createThreadPool() {
+    return new ThreadPoolExecutor(
+            AnalysisConst.DEFAULT_RUN_THREAD_NUM,
+            AnalysisConst.DEFAULT_RUN_THREAD_NUM,
+            AnalysisConst.KEEP_ALIVE_TIME,
+            TimeUnit.MILLISECONDS,
+            new LinkedBlockingQueue<>(AnalysisConst.WORK_QUEUE),
+            new ThreadFactory() {
+                private int count = AnalysisConst.NUM_ZERO;
+                @Override
+                public Thread newThread(Runnable r) {
+                    Thread thread = new Thread(r);
+                    thread.setName("dataForSeo-api-call-thread-" + count++);
+                    thread.setDaemon(true);
+                    return thread;
+                }
+            },
+            new ThreadPoolExecutor.CallerRunsPolicy()
+    );
+}
+    private void shutdownThreadPool(ThreadPoolExecutor executor) {
+        executor.shutdown();
+        try {
+            if (!executor.awaitTermination(AnalysisConst.NUM_TEN, TimeUnit.SECONDS)) {
+                executor.shutdownNow();
+            }
+        } catch (InterruptedException e) {
+            executor.shutdownNow();
+        }
+    }
+
+
+
+/***
+ * @description: 接口1
+ * @param header 请求头
+ * @param keywords 关键词
+ * @param locationName 目标市场
+ * @return: com.slodon.b2b2c.investment.bean.vo.KeyWordPartVO
+ * @author sunshihao
+ * @date: 2025/8/7 11:54
+ */
+public KeyWordPartVO searchVolume(HashMap<String,String> header,String keywords,String locationName) throws Exception {
+    KeyWordPartVO keyWordPartVO = new KeyWordPartVO();
+    JSONArray payload = new JSONArray();
+    JSONObject payloadItem = new JSONObject();
+    JSONArray keywordsArray = new JSONArray();
+    keywordsArray.add(keywords);
+    payloadItem.set(AnalysisConst.KEYWORDS, keywordsArray);
+    payloadItem.set(AnalysisConst.LANGUAGE_NAME, AnalysisConst.ENGLISH);
+    payloadItem.set(AnalysisConst.LOCATION_NAME, locationName);
+    payload.put(payloadItem);
+    String post = HttpClientUtil.httpPost(analysisConfig.getSearchVolume(), payload.toString(),header);
+    JSONObject postObject = JSONUtil.parseObj(post);
+    Integer tasksError = postObject.getByPath("tasks_error", Integer.class);
+    if(tasksError==null||tasksError> AnalysisConst.NUM_ZERO){
+        throw new RuntimeException("接口1查询关键词 按月返回搜索量/CPC search_volume 任务失败");
+    }
+    MonthlySearchesBO bo = postObject.getByPath("tasks[0].result[0].monthly_searches[0]", MonthlySearchesBO.class);
+    Double competition = postObject.getByPath("tasks[0].result[0].competition",Double.class);
+    Integer cp = competition==null?null:(int)Math.round(competition * AnalysisConst.NUM_ONE_HUNDRED);
+    keyWordPartVO.setMonthlySearchesBO(bo);
+    keyWordPartVO.setCompetition(cp);
+    return keyWordPartVO;
+}
+
+
+/***
+ * @description: 上方右侧推荐数据
+ * @param:
+ * @param header 请求头
+ * @param keyword 关键词
+ * @param locationName 地区
+ * @return: com.slodon.b2b2c.investment.bean.vo.SuggestionVO
+ * @author sunshihao
+ * @date: 2025/8/7 15:49
+ */
+public SuggestionVO KeywordForSuggestions(HashMap<String,String> header, String keyword, String locationName) throws Exception {
+    SuggestionVO suggestionVO = new SuggestionVO();
+    JSONArray payload = new JSONArray();
+    JSONObject payloadItem = new JSONObject();
+    payloadItem.set(AnalysisConst.KEYWORD, keyword);
+    payloadItem.set(AnalysisConst.LANGUAGE_NAME, AnalysisConst.ENGLISH);
+    payloadItem.set(AnalysisConst.LOCATION_NAME, locationName);
+    payloadItem.set("include_serp_info", true);
+    payloadItem.set("include_seed_keyword", true);
+    payloadItem.set("include_seed_keyword", true);
+    payloadItem.set(AnalysisConst.LIMIT, AnalysisConst.NUM_TEN);
+    payload.put(payloadItem);
+    String post = HttpClientUtil.httpPost(analysisConfig.getKeywordForSuggestions(), payload.toString(),header);
+    JSONObject postObject = JSONUtil.parseObj(post);
+    Integer tasksError = postObject.getByPath("tasks_error", Integer.class);
+    if(tasksError==null||tasksError> AnalysisConst.NUM_ZERO){
+        throw new RuntimeException("接口5查询推荐数据 任务失败");
+    }
+    JSONArray jsonArray = postObject.getByPath("tasks[0].result[0].items", JSONArray.class);
+    if(jsonArray==null|| jsonArray.isEmpty()){
+        return suggestionVO;
+    }
+    List<RelatedInfoBO> relatedInfoBOList = new ArrayList<>();
+    for (Object o : jsonArray) {
+        RelatedInfoBO bo = new RelatedInfoBO();
+        JSONObject obj = (JSONObject) o;
+        bo.setKeyword(obj.getByPath(AnalysisConst.KEYWORD, String.class));
+        bo.setSearchVolume(obj.getByPath("keyword_info.search_volume", Long.class));
+        Double competition = obj.getByPath("keyword_info.competition", Double.class);
+        bo.setCompetition(competition==null?null:(int)Math.round(competition * AnalysisConst.NUM_ONE_HUNDRED));
+        relatedInfoBOList.add(bo);
+    }
+    suggestionVO.setRelatedInfoBOList(relatedInfoBOList);
+    return suggestionVO;
+}
+
+
+
+
+    public RivalPartVO rival(HashMap<String, String> header, RivalDTO dto) throws Exception {
+        String websites = dto.getCompetitorWebsite();
+        String[] competitorWebsites = websites.split(",");
+        RivalPartVO vo = new RivalPartVO();
+        if(competitorWebsites.length== AnalysisConst.NUM_ZERO){
+            throw new Exception("竞品网站地址不正确");
+        }
+        List<CompetitorBO> competitorBOS = new ArrayList<>();
+        ThreadPoolExecutor executor = createThreadPool();
+        try {
+            for (String competitorWebsite : competitorWebsites) {
+                CompetitorBO bo = new CompetitorBO();
+                bo.setWebsite(competitorWebsite);
+                // 推荐投放关键词表格(接口3)
+                CompletableFuture<List<RecommendationBO>> recommendationBOListFuture = CompletableFuture.supplyAsync(
+                        () -> {
+                            try {
+                                return keywordsForSite(header, competitorWebsite, dto.getLocationName());
+                            } catch (Exception e) {
+                                throw new RuntimeException(e);
+                            }
+                        },
+                        executor
+                );
+                // 折线图表格(接口8)
+                CompletableFuture<List<TrafficBO>> trafficBOListFuture = CompletableFuture.supplyAsync(
+                        () -> {
+                            try {
+                                return historicalTraffic(header, competitorWebsite, dto.getLocationName());
+                            } catch (Exception e) {
+                                throw new RuntimeException(e);
+                            }
+                        },
+                        executor
+                );
+                // 排名表格(接口7)
+                CompletableFuture<List<RankBO>> rankBOListFuture = CompletableFuture.supplyAsync(
+                        () -> {
+                            try {
+                                return rankedKeywords(header, competitorWebsite, dto.getLocationName());
+                            } catch (Exception e) {
+                                throw new RuntimeException(e);
+                            }
+                        },
+                        executor
+                );
+                CompletableFuture.allOf(recommendationBOListFuture, trafficBOListFuture,rankBOListFuture).join();
+                bo.setRecommendationBOList(recommendationBOListFuture.get());
+                bo.setTrafficBOList(trafficBOListFuture.join());
+                bo.setRankBOList(rankBOListFuture.get());
+                competitorBOS.add(bo);
+            }
+        }finally {
+            shutdownThreadPool(executor);
+        }
+        vo.setCompetitorBOS(competitorBOS);
+        return vo;
+    }
+
+
+    // 接口7
+    public List<RankBO> rankedKeywords(HashMap<String,String> header,String website,String locationName) throws Exception {
+        JSONArray payload = new JSONArray();
+        JSONObject payloadItem = new JSONObject();
+        payloadItem.set(AnalysisConst.TARGET, website);
+        payloadItem.set(AnalysisConst.LANGUAGE_NAME, AnalysisConst.ENGLISH);
+        payloadItem.set(AnalysisConst.LOCATION_NAME, locationName);
+        payload.put(payloadItem);
+        String post = HttpClientUtil.httpPost(analysisConfig.getRankedKeywords(), payload.toString(),header);
+        JSONObject postObject = JSONUtil.parseObj(post);
+        Integer tasksError = postObject.getByPath("tasks_error", Integer.class);
+        if(tasksError==null||tasksError> AnalysisConst.NUM_ZERO){
+            throw new RuntimeException("接口7查询 关键词排名 任务失败");
+        }
+        JSONArray items = postObject.getByPath("tasks[0].result[0].items", JSONArray.class);
+        List<RankBO> list = new ArrayList<>();
+        if(items==null|| items.isEmpty()){
+            return list;
+        }
+        for (Object item : items) {
+            JSONObject obj = (JSONObject) item;
+            String keyword = obj.getByPath("keyword_data.keyword", String.class);
+            Long searchVolume = obj.getByPath("keyword_data.keyword_info.search_volume", Long.class);
+            Double competition = obj.getByPath("keyword_data.keyword_info.competition", Double.class);
+            Integer dp = competition==null?null:(int)Math.round(competition * AnalysisConst.NUM_ONE_HUNDRED);
+            Double cpc = obj.getByPath("keyword_data.keyword_info.cpc", Double.class);
+            Double cpcFormat=cpc==null?null:Math.round(cpc * AnalysisConst.NUM_ONE_HUNDRED) / AnalysisConst.ONE_HUNDRED_DOUBLE;
+            Long monthly = obj.getByPath("keyword_data.keyword_info.search_volume_trend.monthly", Long.class);
+            Long quarterly = obj.getByPath("keyword_data.keyword_info.search_volume_trend.quarterly", Long.class);
+            Long yearly = obj.getByPath("keyword_data.keyword_info.search_volume_trend.yearly", Long.class);
+            RankBO bo = RankBO.builder()
+                    .keyword(keyword)
+                    .searchVolume(searchVolume)
+                    .monthly(monthly)
+                    .quarterly(quarterly)
+                    .yearly(yearly)
+                    .dp(dp)
+                    .cpc(cpcFormat)
+                    .build();
+            list.add(bo);
+        }
+        return list;
+    }
+
+    // 接口8
+    public List<TrafficBO> historicalTraffic(HashMap<String,String> header,String website,String locationName) throws Exception {
+        JSONArray payload = new JSONArray();
+        JSONObject payloadItem = new JSONObject();
+        JSONArray targets = new JSONArray();
+        String keyword = StringUtils.removeStart(
+            StringUtils.removeStart(
+                StringUtils.removeStart(website, AnalysisConst.HTTPS),
+                    AnalysisConst.HTTP),
+                AnalysisConst.WWW);
+        int comIndex = keyword.indexOf(AnalysisConst.COM);
+        if (comIndex != -AnalysisConst.NEGATIVE_ONE) {
+            keyword =  keyword.substring(AnalysisConst.NUM_ZERO, comIndex+ AnalysisConst.NUM_FOUR);
+        }
+        targets.add(keyword);
+        payloadItem.set(AnalysisConst.TARGETS,targets);
+        payloadItem.set(AnalysisConst.LANGUAGE_NAME, AnalysisConst.ENGLISH);
+        payloadItem.set(AnalysisConst.LOCATION_NAME, locationName);
+        payload.put(payloadItem);
+        LocalDate currentDate = LocalDate.now();
+        LocalDate currentMonthFirstDay = currentDate.withDayOfMonth(AnalysisConst.NUM_ONE);
+        LocalDate lastYearSameMonthFirstDay = currentDate.minusYears(AnalysisConst.NUM_ONE).plusMonths(AnalysisConst.NUM_ONE).withDayOfMonth(AnalysisConst.NUM_ONE);
+        DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE;
+        payloadItem.set("date_from", lastYearSameMonthFirstDay.format(formatter));
+        payloadItem.set("date_to", currentMonthFirstDay.format(formatter));
+        JSONArray itemTypes = new JSONArray();
+        itemTypes.put("organic");
+        itemTypes.put("paid");
+        payloadItem.set("item_types", itemTypes);
+        JSONObject postData = new JSONObject();
+        postData.set("0", payloadItem);
+
+        String post = HttpClientUtil.httpPost(analysisConfig.getHistoricalTraffic(), postData.toString(),header);
+        JSONObject postObject = JSONUtil.parseObj(post);
+        Integer tasksError = postObject.getByPath("tasks_error", Integer.class);
+        if(tasksError==null||tasksError> AnalysisConst.NUM_ZERO){
+            throw new RuntimeException("接口8查询 历史流量 任务失败");
+        }
+        List<TrafficBO> list = new ArrayList<>();
+        JSONArray organics = postObject.getByPath("tasks[0].result[0].items[0].metrics.organic", JSONArray.class);
+        JSONArray paids = postObject.getByPath("tasks[0].result[0].items[0].metrics.paid", JSONArray.class);
+        Map<Integer, Long> temp = new HashMap<>();
+        if(organics!=null&&!organics.isEmpty()){
+            for (Object organic : organics) {
+                JSONObject obj = (JSONObject) organic;
+                int month = obj.getByPath("month", Integer.class);
+                long organicCount = obj.getByPath("count", Long.class);
+                temp.put(month,organicCount);
+            }
+        }
+        if(paids!=null&&!paids.isEmpty()){
+            for (Object paid : paids) {
+                TrafficBO bo = new TrafficBO();
+                JSONObject obj = (JSONObject) paid;
+                int month = obj.getByPath("month", Integer.class);
+                long paidCount = obj.getByPath("count", Long.class);
+                long organicCount = temp.get(month);
+                bo.setX_axis(month);
+                bo.setPaid(paidCount);
+                bo.setOrganic(organicCount);
+                list.add(bo);
+            }
+        }
+        Collections.reverse(list);
+        return list;
+    }
+
+    // 接口3
+    public List<RecommendationBO> keywordsForSite(HashMap<String, String> header, String website, String locationName) throws Exception {
+        JSONArray payload = new JSONArray();
+        JSONObject payloadItem = new JSONObject();
+        payloadItem.set(AnalysisConst.TARGET, website);
+        payloadItem.set(AnalysisConst.LANGUAGE_NAME, AnalysisConst.ENGLISH);
+        payloadItem.set(AnalysisConst.LOCATION_NAME, locationName);
+        payloadItem.set(AnalysisConst.LIMIT, AnalysisConst.NUM_FIFTY);
+        payload.put(payloadItem);
+        String post = HttpClientUtil.httpPost(analysisConfig.getKeywordsForSite(), payload.toString(),header);
+        JSONObject postObject = JSONUtil.parseObj(post);
+        Integer tasksError = postObject.getByPath("tasks_error", Integer.class);
+        if(tasksError==null||tasksError> AnalysisConst.NUM_ZERO){
+            throw new RuntimeException("接口3查询 keywordsForSite 任务失败");
+        }
+        List<RecommendationBO> list = new ArrayList<>();
+        JSONArray results = postObject.getByPath("tasks[0].result", JSONArray.class);
+        if(results==null){
+            return list;
+        }
+        int total = Math.min(results.size(), AnalysisConst.NUM_FIFTY);
+        for(int i = AnalysisConst.NUM_ZERO; i<total; i++){
+            JSONObject result = (JSONObject) results.get(i);
+            RecommendationBO bo = new RecommendationBO();
+            bo.setKeywords(result.getByPath(AnalysisConst.KEYWORD,String.class));
+            bo.setSearchVolume(result.getByPath("search_volume",Long.class));
+            Double cpc = result.getByPath("cpc",Double.class);
+            Double cpcFormat=cpc==null?null:Math.round(cpc * AnalysisConst.NUM_ONE_HUNDRED) / AnalysisConst.ONE_HUNDRED_DOUBLE;
+            bo.setPrice(cpcFormat);
+            list.add(bo);
+        }
+        return list;
+    }
+
+    public String qualitative(String keyword) throws Exception {
+        HashMap<String, String> headers = new HashMap<>();
+        headers.put(AnalysisConst.CONTENT_TYPE, AnalysisConst.APPLICATION_JSON);
+        JSONObject param = new JSONObject();
+        param.set("question", keyword);
+        param.set("initial_search_query_count", AnalysisConst.NUM_THREE);
+        param.set("max_research_loops", AnalysisConst.NUM_THREE);
+        param.set("reasoning_model", analysisConfig.getModelName());
+        String result;
+        try {
+            result = HttpClientUtil.httpPost(analysisConfig.getTranslateAddress() + "/api/research", param.toString(), headers);
+            JSONObject jsonObject = JSONUtil.parseObj(result);
+            String answer = jsonObject.getByPath("answer",String.class);
+            if(StringUtils.isEmpty(answer)){
+                return "";
+            }
+        return dealAnswer(answer);
+        } catch (Exception e) {
+            log.error(e.getMessage(), "定性分析接口出错");
+            throw new Exception("定性分析接口出错", e);
+        }
+    }
+
+    private String dealAnswer(String answer) {
+        answer = answer.replace(AnalysisConst.CHINESE, "");
+        String lastPart = getLastPart(answer);
+        String firstPart = getFirstPart(answer);
+        return firstPart + lastPart;
+    }
+
+    private String getLastPart(String answer) {
+        int startIndex = answer.indexOf (AnalysisConst.LAST_PART_MARKER);
+        if (startIndex != AnalysisConst.NEGATIVE_ONE) {
+            return answer.substring (startIndex);
+        } else {
+            return "";
+        }
+    }
+
+    public String getFirstPart (String input) {
+        int markerIndex = input.indexOf (AnalysisConst.FIRST_MARKER);
+        if (markerIndex != AnalysisConst.NEGATIVE_ONE) {
+            return input.substring (AnalysisConst.NUM_ZERO, markerIndex);
+        } else {
+            return input;
+        }
+    }
+}
+
+
+

+ 6 - 0
xinkeaboard-server/b2b2c-web/pom.xml

@@ -24,6 +24,12 @@
             <version>3.0</version>
         </dependency>
 
+        <dependency>
+            <groupId>com.slodon</groupId>
+            <artifactId>b2b2c-investment</artifactId>
+            <version>3.0</version>
+        </dependency>
+
         <!--    bbc common    -->
         <dependency>
             <groupId>com.slodon</groupId>

+ 3 - 2
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/goods/seller/GoodsCategorySellerController.java

@@ -130,10 +130,11 @@ public class GoodsCategorySellerController {
     @GetMapping("listByPId")
     public JsonResult<List<FrontGoodsCategoryVO>> listByPId(HttpServletRequest request,
                                                             @RequestParam(value = "categoryId", defaultValue = "0") Integer categoryId,
-                                                            @RequestParam(value = "grade", defaultValue = "1") Integer grade) {
+                                                            @RequestParam(value = "grade", defaultValue = "1") Integer grade,
+                                                            @RequestParam(value = "webSite",required = false, defaultValue = "1") String webSite) {
         List<FrontGoodsCategoryVO> vos = new ArrayList<>();
         //查询redis缓存
-        String dataJson = stringRedisTemplate.opsForValue().get(RedisConst.FRONT_GOODS_CATEGORY);
+        String dataJson = stringRedisTemplate.opsForValue().get(RedisConst.FRONT_GOODS_CATEGORY + "_" + webSite);
         if (!StringUtils.isEmpty(dataJson)) {
             JSONArray jsonArray = JSONArray.parseArray(dataJson);
             for (int i = 0; i < jsonArray.size(); i++) {

+ 4 - 3
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/member/admin/AdminEnquiryController.java

@@ -97,15 +97,16 @@ public class AdminEnquiryController extends BaseController {
                                                       @RequestParam(value = "email", required = false) String email,
                                                       @RequestParam(value = "validStatus", required = false) Integer validStatus,
                                                       @RequestParam(value = "storeId", required = false) Long storeId,
-                                                      @RequestParam(value = "webSite", required = false) String webSite) {
+                                                      @RequestParam(value = "webSite", required = false) String webSite,
+                                                      @RequestParam(value = "phone", required = false) String phone) {
         Admin admin = UserUtil.getUser(request, Admin.class);
 
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
         if(storeId !=null && storeId == 1){
             storeId = 0L;
         }
-        List<MemberEnquiry> list = memberEnquiryModel.getEnquiryAdminListByPage(name, email, String.valueOf(admin.getIsSuper()), admin.getAdminId(),validStatus, pager,storeId,webSite);
-        pager.setRowsCount(memberEnquiryModel.enquiryAdminListPageCount(name, email, String.valueOf(admin.getIsSuper()), admin.getAdminId(),validStatus,storeId,webSite));
+        List<MemberEnquiry> list = memberEnquiryModel.getEnquiryAdminListByPage(name, email, String.valueOf(admin.getIsSuper()), admin.getAdminId(),validStatus, pager,storeId,webSite,phone);
+        pager.setRowsCount(memberEnquiryModel.enquiryAdminListPageCount(name, email, String.valueOf(admin.getIsSuper()), admin.getAdminId(),validStatus,storeId,webSite,phone));
         ArrayList<OrderEnquiryVO> vos = new ArrayList<>();
         if (!CollectionUtils.isEmpty(list)) {
             list.forEach(memberEnquiry -> {

+ 1 - 1
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/member/front/advich/MemberEmailActiveController.java

@@ -339,7 +339,7 @@ public class MemberEmailActiveController extends BaseController {
             AssertUtil.emailCheck(email);
         } else if (WebSiteConstant.MEMBER_DISTRIBUTOR.equals(webSite)) {
             if (StringUtil.isEmpty(mobile)) {
-                return ValidationResult.invalid(Language.translate("手机不能为空", Language.EN_LANGUAGE_TYPE));
+                return ValidationResult.invalid(Language.translate("手机不能为空", Language.EN_LANGUAGE_TYPE));
             }
             if (StringUtil.isEmpty(verificationCode)) {
                 return ValidationResult.invalid(Language.translate("验证码不能为空", Language.EN_LANGUAGE_TYPE));

+ 3 - 3
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/member/seller/advich/SellerEnquiryController.java

@@ -71,12 +71,12 @@ public class SellerEnquiryController extends BaseController {
      * @return
      */
     @GetMapping("list")
-    public JsonResult<PageVO<OrderEnquiryVO>> getList(HttpServletRequest request, @RequestParam(value = "name", required = false) String name, @RequestParam(value = "email", required = false) String email, @RequestParam(value = "validStatus", required = false) Integer validStatus, @RequestParam(value = "webSite", required = false,defaultValue = "1") String webSite) {
+    public JsonResult<PageVO<OrderEnquiryVO>> getList(HttpServletRequest request, @RequestParam(value = "name", required = false) String name, @RequestParam(value = "email", required = false) String email, @RequestParam(value = "validStatus", required = false) Integer validStatus, @RequestParam(value = "webSite", required = false,defaultValue = "1") String webSite,@RequestParam(value = "phone", required = false) String phone ) {
         Vendor vendor = UserUtil.getUser(request, Vendor.class);
 
         PagerInfo pager = WebUtil.handlerPagerInfo(request);
-        List<MemberEnquiry> list = memberEnquiryModel.getEnquiryListByPage(name, email, vendor.getStoreId(), vendor.getIsStoreAdmin(), vendor.getVendorId(), validStatus,webSite, pager);
-        pager.setRowsCount(memberEnquiryModel.enquiryListPageCount(name, email, vendor.getStoreId(), vendor.getIsStoreAdmin(), vendor.getVendorId(), validStatus,webSite));
+        List<MemberEnquiry> list = memberEnquiryModel.getEnquiryListByPage(name, email, vendor.getStoreId(), vendor.getIsStoreAdmin(), vendor.getVendorId(), validStatus, webSite, phone, pager);
+        pager.setRowsCount(memberEnquiryModel.enquiryListPageCount(name, email, vendor.getStoreId(), vendor.getIsStoreAdmin(), vendor.getVendorId(), validStatus, webSite, phone));
         ArrayList<OrderEnquiryVO> vos = new ArrayList<>();
         if (!CollectionUtils.isEmpty(list)) {
             list.forEach(memberEnquiry -> {

+ 5 - 0
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/msg/front/VerifyController.java

@@ -20,6 +20,7 @@ import com.slodon.b2b2c.model.member.MemberModel;
 import com.slodon.b2b2c.model.msg.MsgSendModel;
 import com.slodon.b2b2c.model.msg.SmsCodeModel;
 import com.slodon.b2b2c.msg.pojo.SmsCode;
+import com.slodon.b2b2c.sms.DySmsSender;
 import com.slodon.b2b2c.sms.TencentSmsSender;
 import com.slodon.b2b2c.sms.YunPianSmsSender;
 import com.slodon.b2b2c.sms.base.SmsSender;
@@ -200,6 +201,10 @@ public class VerifyController extends BaseController {
                 //云片发送
                 smsSender = new YunPianSmsSender(stringRedisTemplate);
                 break;
+            case 3:
+                //阿里云发送
+                smsSender = new DySmsSender(stringRedisTemplate);
+                break;
             default:
                 throw new MallException("发送短信失败");
         }

+ 2 - 2
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/sso/front/FrontAuthController.java

@@ -129,11 +129,11 @@ public class FrontAuthController {
                 } else {
                     AssertUtil.notEmpty(memberList, Language.translate("会员账号或密码错误",Language.EN_LANGUAGE_TYPE));
                     if (ssoType != null && ssoType == 1) {
-                        AssertUtil.isTrue(!memberList.get(0).getLoginPwd().equals(password), Language.translate("会员邮箱或密码错误",Language.EN_LANGUAGE_TYPE));
+                        AssertUtil.isTrue(!memberList.get(0).getLoginPwd().equals(password), Language.translate("会员账号或密码错误",Language.EN_LANGUAGE_TYPE));
                     } else {
                         oneClickLoginModel.checkGpSystemUserIsExist(request, username, password, "PC", webSite);
                         memberList = memberModel.getMemberList(memberExample, null);
-                        AssertUtil.isTrue(!memberList.get(0).getLoginPwd().equals(Md5.getMd5String(password)), Language.translate("会员邮箱或密码错误",Language.EN_LANGUAGE_TYPE));
+                        AssertUtil.isTrue(!memberList.get(0).getLoginPwd().equals(Md5.getMd5String(password)), Language.translate("会员账号或密码错误",Language.EN_LANGUAGE_TYPE));
                     }
                 }
             } else {

+ 6 - 6
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/system/admin/SearchInitController.java

@@ -36,11 +36,11 @@ public class SearchInitController {
     @ApiOperation("初始化es索引")
     @OperationLogger(option = "初始化es索引")
     @GetMapping("esInit")
-    public JsonResult esInit() throws IOException {
+    public JsonResult esInit(String webSite) throws IOException {
         //删除索引
-        deleteByQuery();
+        deleteByQuery(webSite);
         //重新把索引生成
-        esGoodsModel.jobCreateIndexesES(DomainUrlUtil.SLD_ES_URL, DomainUrlUtil.SLD_ES_PORT, "init");
+        esGoodsModel.jobCreateIndexesES(DomainUrlUtil.SLD_ES_URL, DomainUrlUtil.SLD_ES_PORT, "init", webSite);
 
         return SldResponse.success("初始化成功");
     }
@@ -58,12 +58,12 @@ public class SearchInitController {
     /**
      * 删除索引
      */
-    private static void deleteByQuery() throws IOException {
+    private static void deleteByQuery(String webSite) throws IOException {
         RestHighLevelClient client = getESClient();
-        boolean indexExist = client.indices().exists(new GetIndexRequest(DomainUrlUtil.ES_INDEX_NAME), RequestOptions.DEFAULT);
+        boolean indexExist = client.indices().exists(new GetIndexRequest(DomainUrlUtil.ES_INDEX_NAME + "_" + webSite), RequestOptions.DEFAULT);
         if (indexExist) {
             //索引存在,删除索引
-            DeleteByQueryRequest request = new DeleteByQueryRequest(DomainUrlUtil.ES_INDEX_NAME);
+            DeleteByQueryRequest request = new DeleteByQueryRequest(DomainUrlUtil.ES_INDEX_NAME + "_" + webSite);
             request.setConflicts("proceed");
             request.setQuery(QueryBuilders.matchAllQuery());
             client.deleteByQuery(request, RequestOptions.DEFAULT);

+ 4 - 0
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/dao/read/goods/GoodsExtendReadMapper.java

@@ -3,6 +3,10 @@ package com.slodon.b2b2c.dao.read.goods;
 import com.slodon.b2b2c.core.database.BaseReadMapper;
 import com.slodon.b2b2c.goods.example.GoodsExtendExample;
 import com.slodon.b2b2c.goods.pojo.GoodsExtend;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 public interface GoodsExtendReadMapper extends BaseReadMapper<GoodsExtend, GoodsExtendExample> {
+    List<GoodsExtend> listResByExample(@Param("example") GoodsExtendExample example);
 }

+ 18 - 3
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/dao/read/member/MemberEnquiryReadMapper.java

@@ -22,6 +22,9 @@ public interface MemberEnquiryReadMapper extends BaseReadMapper<MemberEnquiry, M
      * @param storeId
      * @param isStoreAdmin
      * @param vendorId
+     * @param validStatus
+     * @param webSite
+     * @param phone
      * @param startRow
      * @param size
      * @return
@@ -33,6 +36,7 @@ public interface MemberEnquiryReadMapper extends BaseReadMapper<MemberEnquiry, M
                                         @Param("vendorId") Long vendorId,
                                         @Param("validStatus") Integer validStatus,
                                         @Param("webSite") String webSite,
+                                        @Param("phone") String phone,
                                         @Param("startRow") Integer startRow,
                                         @Param("size") Integer size);
 
@@ -44,6 +48,9 @@ public interface MemberEnquiryReadMapper extends BaseReadMapper<MemberEnquiry, M
      * @param storeId
      * @param isStoreAdmin
      * @param vendorId
+     * @param webSite
+     * @param validStatus
+     * @param phone
      * @return
      */
     Integer enquiryListPageCount(@Param("nameLike") String name,
@@ -52,7 +59,8 @@ public interface MemberEnquiryReadMapper extends BaseReadMapper<MemberEnquiry, M
                                  @Param("isStoreAdmin") String isStoreAdmin,
                                  @Param("vendorId") Long vendorId,
                                  @Param("validStatus") Integer validStatus,
-                                 @Param("webSite") String webSite);
+                                 @Param("webSite") String webSite,
+                                 @Param("phone") String phone);
 
 
     /**
@@ -63,6 +71,9 @@ public interface MemberEnquiryReadMapper extends BaseReadMapper<MemberEnquiry, M
      * @param isSupAdmin
      * @param sysAdminId
      * @param validStatus
+     * @param webSite
+     * @param storeId
+     * @param phone
      * @param startRow
      * @param size
      * @return
@@ -75,7 +86,8 @@ public interface MemberEnquiryReadMapper extends BaseReadMapper<MemberEnquiry, M
                                              @Param("startRow") Integer startRow,
                                              @Param("size") Integer size,
                                              @Param("storeId") Long storeId,
-                                             @Param("webSite") String webSite);
+                                             @Param("webSite") String webSite,
+                                             @Param("phone") String phone);
 
     /**
      * 平台端-询盘数量
@@ -86,6 +98,8 @@ public interface MemberEnquiryReadMapper extends BaseReadMapper<MemberEnquiry, M
      * @param sysAdminId
      * @param validStatus
      * @param webSite
+     * @param storeId
+     * @param phone
      * @return
      */
     Integer enquiryAdminListPageCount(@Param("nameLike") String name,
@@ -94,7 +108,8 @@ public interface MemberEnquiryReadMapper extends BaseReadMapper<MemberEnquiry, M
                                       @Param("sysAdminId") Integer sysAdminId,
                                       @Param("validStatus") Integer validStatus,
                                       @Param("storeId") Long storeId,
-                                      @Param("webSite") String webSite);
+                                      @Param("webSite") String webSite,
+                                      @Param("phone") String phone);
 
     /**
      * 卖家端-询盘趋势-天数

+ 1 - 1
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/interceptor/BearerTokenConfiguration.java

@@ -13,7 +13,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  */
 @Configuration
 public class BearerTokenConfiguration implements WebMvcConfigurer {
-    public static String[] urlList = new String[]{"/openapi/**"};
+    public static String[] urlList = new String[]{"/openapi/**","/analysis/**"};
 
     @Bean
     public BearerTokenInterceptor tokenConfiguration(){

+ 15 - 5
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/job/GoodsJob.java

@@ -8,7 +8,9 @@ import com.slodon.b2b2c.model.goods.ESGoodsModel;
 import com.slodon.b2b2c.model.goods.GoodsPromotionModel;
 import com.slodon.b2b2c.model.goods.GoodsRankModel;
 import com.slodon.b2b2c.model.goods.ProductModel;
+import com.slodon.b2b2c.model.system.SettingModel;
 import com.slodon.b2b2c.starter.mq.entity.MessageSendVO;
+import com.slodon.b2b2c.system.pojo.Setting;
 import lombok.extern.slf4j.Slf4j;
 import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
 import org.springframework.amqp.rabbit.core.RabbitTemplate;
@@ -40,6 +42,8 @@ public class GoodsJob {
     private GoodsRankModel goodsRankModel;
     @Resource
     private RabbitTemplate rabbitTemplate;
+    @Resource
+    private SettingModel settingModel;
 
     /**
      * 系统定时更新es索引
@@ -49,11 +53,17 @@ public class GoodsJob {
     @SchedulerLock(name = "jobSearchES", lockAtMostFor = "600000", lockAtLeastFor = "540000")
     public void jobSearchES() {
         log.info("jobSearchES() start");
-        try {
-            boolean jobResult = esGoodsModel.jobCreateIndexesES(DomainUrlUtil.SLD_ES_URL, DomainUrlUtil.SLD_ES_PORT, "job");
-            AssertUtil.isTrue(!jobResult, "[jobSearchES] 系统定时任务定时生成ES索引失败");
-        } catch (Exception e) {
-            log.error("jobSearchES()", e);
+        List<Setting> webSiteList = settingModel.getSiteSetting();
+        if (!CollectionUtils.isEmpty(webSiteList)) {
+            for (Setting setting : webSiteList) {
+                log.info("jobSearchES() start");
+                try {
+                    boolean jobResult = esGoodsModel.jobCreateIndexesES(DomainUrlUtil.SLD_ES_URL, DomainUrlUtil.SLD_ES_PORT, "job", setting.getValue());
+                    AssertUtil.isTrue(!jobResult, "[jobSearchES] 系统定时任务定时生成ES索引失败");
+                } catch (Exception e) {
+                    log.error("jobSearchES()", e);
+                }
+            }
         }
         log.info("jobSearchES() end");
     }

+ 85 - 64
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/model/goods/ESGoodsModel.java

@@ -18,18 +18,17 @@ import com.slodon.b2b2c.dao.read.goods.*;
 import com.slodon.b2b2c.dao.read.member.MemberFollowProductReadMapper;
 import com.slodon.b2b2c.dao.read.seller.StoreInnerLabelReadMapper;
 import com.slodon.b2b2c.dao.read.seller.StoreLabelBindGoodsReadMapper;
+import com.slodon.b2b2c.enums.WebSiteConstant;
 import com.slodon.b2b2c.goods.dto.GoodsRankListDTO;
 import com.slodon.b2b2c.goods.dto.SearchConditionDTO;
-import com.slodon.b2b2c.goods.example.GoodsBindAttributeValueExample;
-import com.slodon.b2b2c.goods.example.GoodsBindRankExample;
-import com.slodon.b2b2c.goods.example.GoodsExample;
-import com.slodon.b2b2c.goods.example.GoodsPromotionExample;
+import com.slodon.b2b2c.goods.example.*;
 import com.slodon.b2b2c.goods.pojo.*;
 import com.slodon.b2b2c.member.example.MemberFollowProductExample;
 import com.slodon.b2b2c.member.pojo.Member;
 import com.slodon.b2b2c.member.pojo.MemberFollowProduct;
 import com.slodon.b2b2c.model.promotion.PromotionCommonModel;
 import com.slodon.b2b2c.model.system.SettingModel;
+import com.slodon.b2b2c.seller.example.StoreInnerLabelExample;
 import com.slodon.b2b2c.seller.example.StoreLabelBindGoodsExample;
 import com.slodon.b2b2c.seller.pojo.StoreInnerLabel;
 import com.slodon.b2b2c.seller.pojo.StoreLabelBindGoods;
@@ -78,6 +77,7 @@ import javax.annotation.Resource;
 import java.io.IOException;
 import java.math.BigDecimal;
 import java.util.*;
+import java.util.stream.Collectors;
 
 import static com.alibaba.fastjson.serializer.SerializerFeature.MapSortField;
 import static com.alibaba.fastjson.serializer.SerializerFeature.SortField;
@@ -121,11 +121,15 @@ public class ESGoodsModel {
      * @return
      */
     @SneakyThrows
-    public boolean jobCreateIndexesES(String url, Integer port, String type) {
+    public boolean jobCreateIndexesES(String url, Integer port, String type, String webSite) {
         //es索引上次更新的时间
         String esIndexUpdateTime = stringRedisTemplate.opsForValue().get("es_index_update_time");
+        if (WebSiteConstant.MEMBER_DISTRIBUTOR.equals(webSite)) {
+            esIndexUpdateTime = stringRedisTemplate.opsForValue().get("es_index_update_time" + "_" + webSite);
+        }
 
         GoodsExample example = new GoodsExample();
+        example.setWebSite(webSite);
         example.setState(GoodsConst.GOODS_STATE_UPPER);
         if ("job".equals(type)) {
             example.setUpdateTimeAfter(TimeUtil.strToDate(esIndexUpdateTime));
@@ -134,7 +138,7 @@ public class ESGoodsModel {
 
         if (!CollectionUtils.isEmpty(addList)) {
             List<SearchProductDTO> addGoodsList = this.getSearchProductVOs(addList);
-            BulkResponse response = this.createIndex(url, port, addGoodsList);
+            BulkResponse response = this.createIndex(url, port, addGoodsList, webSite);
             if (response.hasFailures()) {
                 //索引插入数据失败
                 log.error(response.buildFailureMessage());
@@ -144,11 +148,12 @@ public class ESGoodsModel {
         if ("job".equals(type)) {
             //下架状态的商品,执行删除索引记录操作
             example.setState(null);
+            example.setWebSite(webSite);
             example.setStateNotEquals(GoodsConst.GOODS_STATE_UPPER);
             //需要删除索引记录的商品列表
             List<Goods> deleteList = goodsReadMapper.listByExample(example);
             if (!CollectionUtils.isEmpty(deleteList)) {
-                this.deleteByQuery(url, port, deleteList);
+                this.deleteByQuery(url, port, deleteList, webSite);
             }
         }
 
@@ -156,10 +161,16 @@ public class ESGoodsModel {
         String updateTime = TimeUtil.getDateTimeString(new Date());
         Setting setting = new Setting();
         setting.setName("es_index_update_time");
+        if (WebSiteConstant.MEMBER_DISTRIBUTOR.equals(webSite)) {
+            setting.setName("es_index_update_time" + "_" + webSite);
+        }
         setting.setValue(updateTime);
         settingModel.updateSetting(setting);
         //更新redis里的配置
         stringRedisTemplate.opsForValue().set("es_index_update_time", updateTime);
+        if (WebSiteConstant.MEMBER_DISTRIBUTOR.equals(webSite)) {
+            stringRedisTemplate.opsForValue().set("es_index_update_time" + "_" + webSite, updateTime);
+        }
         return true;
     }
 
@@ -172,6 +183,25 @@ public class ESGoodsModel {
     private List<SearchProductDTO> getSearchProductVOs(List<Goods> goodsList) {
         List<SearchProductDTO> searchProductDTOS = new ArrayList<>();
         SearchProductDTO searchProductDTO;
+        GoodsCategoryExample goodsCategoryExample = new GoodsCategoryExample();
+        goodsCategoryExample.setGrade(GoodsCategoryConst.CATEGORY_GRADE_3);
+        List<GoodsCategory> categoryList = goodsCategoryReadMapper.listByExample(goodsCategoryExample);
+        List<GoodsBindAttributeValue> bindAttributeValueListAll = goodsBindAttributeValueReadMapper.listByExample(new GoodsBindAttributeValueExample());
+        List<GoodsExtend> goodsExtendList = goodsExtendModel.listByExample(new GoodsExtendExample());
+        List<StoreLabelBindGoods> labelBindGoodsListAll = storeLabelBindGoodsReadMapper.listByExample(new StoreLabelBindGoodsExample());
+        List<StoreInnerLabel> storeInnerLabelList = storeInnerLabelReadMapper.listByExample(new StoreInnerLabelExample());
+        List<GoodsRankListDTO> rankListAll = goodsBindRankReadMapper.getGoodsRankList(new GoodsBindRankExample());
+        GoodsPromotionExample promotionExample = new GoodsPromotionExample();
+        promotionExample.setIsEffective(PromotionConst.IS_EFFECTIVE_YES);
+        promotionExample.setStartTimeBefore(new Date());
+        promotionExample.setEndTimeAfter(new Date());
+        //一级活动,绑定商品
+        promotionExample.setBindType(PromotionConst.BIND_TYPE_1);
+        List<GoodsPromotion> listAll = goodsPromotionReadMapper.listByExample(promotionExample);
+        promotionExample.setBindType(PromotionConst.BIND_TYPE_2);
+        List<GoodsPromotion> secondListAll = goodsPromotionReadMapper.listByExample(promotionExample);
+        promotionExample.setBindType(PromotionConst.BIND_TYPE_3);
+        List<GoodsPromotion> thirdListAll = goodsPromotionReadMapper.listByExample(promotionExample);
         for (Goods goods : goodsList) {
             searchProductDTO = new SearchProductDTO();
             searchProductDTO.setGoodsId(goods.getGoodsId().toString());
@@ -187,8 +217,10 @@ public class ESGoodsModel {
             searchProductDTO.setCategoryId3(goods.getCategoryId3().toString());
             searchProductDTO.setGoodsMoney(goods.getGoodsMoney());
             searchProductDTO.setGoodsSummary(goods.getGoodsSummary());
-            GoodsCategory goodsCategory = goodsCategoryReadMapper.getByPrimaryKey(goods.getCategoryId3());
-            searchProductDTO.setCategoryName(goodsCategory.getCategoryName());
+            GoodsCategory goodsCategory = categoryList.stream().filter(category -> category.getCategoryId().equals(goods.getCategoryId3())).findFirst().orElse(null);
+            if (goodsCategory != null) {
+                searchProductDTO.setCategoryName(goodsCategory.getCategoryName());
+            }
             searchProductDTO.setContent(goods.getGoodsBrief());
             searchProductDTO.setDefaultProductId(goods.getDefaultProductId());
 
@@ -199,49 +231,49 @@ public class ESGoodsModel {
             searchProductDTO.setCommentsNumber(goods.getCommentNumber());
 
             //商品的系统属性
-            GoodsBindAttributeValueExample valueExample = new GoodsBindAttributeValueExample();
-            valueExample.setGoodsId(goods.getGoodsId());
-            List<GoodsBindAttributeValue> bindAttributeValueList = goodsBindAttributeValueReadMapper.listByExample(valueExample);
+            List<GoodsBindAttributeValue> bindAttributeValueList = bindAttributeValueListAll.stream().filter(bindAttributeValue -> bindAttributeValue.getGoodsId().equals(goods.getGoodsId())).collect(Collectors.toList());
             if (!CollectionUtils.isEmpty(bindAttributeValueList)) {
                 StringBuffer attributeInfo = new StringBuffer();
                 bindAttributeValueList.forEach(bindAttributeValue -> {
                     attributeInfo.append(" ").append(bindAttributeValue.getAttributeValueId());
                 });
-                searchProductDTO.setAttributeInfo(attributeInfo.toString().substring(1));
+                searchProductDTO.setAttributeInfo(attributeInfo.substring(1));
             }
 
             searchProductDTO.setSalesNum(goods.getVirtualSales() + goods.getActualSales());
             //商品扩展信息
-            GoodsExtend goodsExtend = goodsExtendModel.getGoodsExtendByGoodsId(goods.getGoodsId());
-            searchProductDTO.setClickNum(goodsExtend.getClickNumber());
-            searchProductDTO.setFollowNum(goodsExtend.getFollowNumber());
+            GoodsExtend goodsExtend = goodsExtendList.stream().filter(e -> e.getGoodsId().equals(goods.getGoodsId())).findFirst().orElse(null);
+            if (goodsExtend != null) {
+                searchProductDTO.setClickNum(goodsExtend.getClickNumber());
+                searchProductDTO.setFollowNum(goodsExtend.getFollowNumber());
+            }
             searchProductDTO.setStoreIsRecommend(goods.getStoreIsRecommend());
             searchProductDTO.setIsSelf(goods.getIsSelf());
 
 
             //查询店铺分类绑定商品表
-            StoreLabelBindGoodsExample bindGoodsExample = new StoreLabelBindGoodsExample();
-            bindGoodsExample.setGoodsId(goods.getGoodsId());
-            List<StoreLabelBindGoods> labelBindGoodsList = storeLabelBindGoodsReadMapper.listByExample(bindGoodsExample);
+            List<StoreLabelBindGoods> labelBindGoodsList = labelBindGoodsListAll.stream().filter(bindGoods -> bindGoods.getGoodsId().equals(goods.getGoodsId())).collect(Collectors.toList());
             if (!CollectionUtils.isEmpty(labelBindGoodsList)) {
                 //商家内部一级分类ID
                 StringBuilder storeInnerLabelId1 = new StringBuilder();
                 //商家内部二级分类ID
                 StringBuilder storeInnerLabelId2 = new StringBuilder();
                 for (StoreLabelBindGoods labelBindGoods : labelBindGoodsList) {
-                    StoreInnerLabel storeInnerLabel = storeInnerLabelReadMapper.getByPrimaryKey(labelBindGoods.getInnerLabelId());
-                    if (storeInnerLabel.getParentInnerLabelId() == 0) {
-                        //商品绑定的是一级内部分类
-                        storeInnerLabelId1.append(" ").append(storeInnerLabel.getInnerLabelId());
-                    } else {
-                        //商品绑定的是二级内部分类
-                        storeInnerLabelId2.append(" ").append(storeInnerLabel.getInnerLabelId());
-                        storeInnerLabelId1.append(" ").append(storeInnerLabel.getParentInnerLabelId());
+                    StoreInnerLabel storeInnerLabel = storeInnerLabelList.stream().filter(innerLabel -> innerLabel.getInnerLabelId().equals(labelBindGoods.getInnerLabelId())).findFirst().orElse(null);
+                    if (storeInnerLabel != null) {
+                        if (storeInnerLabel.getParentInnerLabelId() == 0) {
+                            //商品绑定的是一级内部分类
+                            storeInnerLabelId1.append(" ").append(storeInnerLabel.getInnerLabelId());
+                        } else {
+                            //商品绑定的是二级内部分类
+                            storeInnerLabelId2.append(" ").append(storeInnerLabel.getInnerLabelId());
+                            storeInnerLabelId1.append(" ").append(storeInnerLabel.getParentInnerLabelId());
+                        }
                     }
                 }
-                searchProductDTO.setStoreInnerLabelId1(storeInnerLabelId1.toString().substring(1));
+                searchProductDTO.setStoreInnerLabelId1(storeInnerLabelId1.substring(1));
                 if (!StringUtils.isEmpty(storeInnerLabelId2.toString())) {
-                    searchProductDTO.setStoreInnerLabelId2(storeInnerLabelId2.toString().substring(1));
+                    searchProductDTO.setStoreInnerLabelId2(storeInnerLabelId2.substring(1));
                 }
             }
             searchProductDTO.setOnlineTime(goods.getOnlineTime().getTime());
@@ -249,7 +281,7 @@ public class ESGoodsModel {
             //商品排行查询
             GoodsBindRankExample goodsBindRankExample = new GoodsBindRankExample();
             goodsBindRankExample.setGoodsId(goods.getGoodsId());
-            List<GoodsRankListDTO> rankList = goodsBindRankReadMapper.getGoodsRankList(goodsBindRankExample);
+            List<GoodsRankListDTO> rankList = rankListAll.stream().filter(rank -> rank.getGoodsId().equals(goods.getGoodsId())).collect(Collectors.toList());
             if (!CollectionUtils.isEmpty(rankList)) {
                 GoodsRankListDTO goodsRank = rankList.get(0);
                 searchProductDTO.setRankId(goodsRank.getRankId().toString());
@@ -260,24 +292,11 @@ public class ESGoodsModel {
             }
 
             //商品参与的活动
-            GoodsPromotionExample promotionExample = new GoodsPromotionExample();
-            promotionExample.setIsEffective(PromotionConst.IS_EFFECTIVE_YES);
-            promotionExample.setStartTimeBefore(new Date());
-            promotionExample.setEndTimeAfter(new Date());
-            //一级活动,绑定商品
-            promotionExample.setBindType(PromotionConst.BIND_TYPE_1);
-            promotionExample.setGoodsId(goods.getGoodsId());
-            List<GoodsPromotion> list = goodsPromotionReadMapper.listByExample(promotionExample);
+            List<GoodsPromotion> list = listAll.stream().filter(goodsPromotion -> goodsPromotion.getGoodsId().equals(goods.getGoodsId())).collect(Collectors.toList());
             //二级活动,绑定店铺
-            promotionExample.setGoodsId(null);
-            promotionExample.setStoreId(goods.getStoreId());
-            promotionExample.setBindType(PromotionConst.BIND_TYPE_2);
-            list.addAll(goodsPromotionReadMapper.listByExample(promotionExample));
+            list.addAll(secondListAll.stream().filter(goodsPromotion -> goodsPromotion.getStoreId().equals(goods.getStoreId())).collect(Collectors.toList()));
             //三级活动,绑定三级分类
-            promotionExample.setStoreId(null);
-            promotionExample.setGoodsCategoryId3(goods.getCategoryId3());
-            promotionExample.setBindType(PromotionConst.BIND_TYPE_3);
-            list.addAll(goodsPromotionReadMapper.listByExample(promotionExample));
+            list.addAll(thirdListAll.stream().filter(goodsPromotion -> goodsPromotion.getGoodsCategoryId3().equals(goods.getCategoryId3())).collect(Collectors.toList()));
             List<GoodsListVO.PromotionVO> vos = new ArrayList<>();
             //根据活动名称过滤重复
             Set<String> set = new HashSet<>();
@@ -325,15 +344,15 @@ public class ESGoodsModel {
      * @param goodsList
      * @throws IOException
      */
-    private BulkResponse createIndex(String url, Integer port, List<SearchProductDTO> goodsList) throws IOException {
+    private BulkResponse createIndex(String url, Integer port, List<SearchProductDTO> goodsList, String webSite) throws IOException {
         RestHighLevelClient client = null;
         BulkResponse response = null;
         try {
             client = getESClient();
-            boolean indexExist = client.indices().exists(new GetIndexRequest(DomainUrlUtil.ES_INDEX_NAME), RequestOptions.DEFAULT);
+            boolean indexExist = client.indices().exists(new GetIndexRequest(DomainUrlUtil.ES_INDEX_NAME + "_" + webSite), RequestOptions.DEFAULT);
             if (!indexExist) {
                 //索引不存在,创建索引,设置索引分词格式
-                CreateIndexRequest createIndexRequest = new CreateIndexRequest(DomainUrlUtil.ES_INDEX_NAME);
+                CreateIndexRequest createIndexRequest = new CreateIndexRequest(DomainUrlUtil.ES_INDEX_NAME + "_" + webSite);
                 createIndexRequest.settings(Settings.builder()
                         .put("index.analysis.analyzer.default.type", "ik_max_word")
                         .put("index.analysis.analyzer.default_search.type", "ik_smart"));
@@ -342,7 +361,7 @@ public class ESGoodsModel {
             BulkRequest bulkRequest = new BulkRequest();
             //插入数据
             for (SearchProductDTO g : goodsList) {
-                bulkRequest.add(new IndexRequest(DomainUrlUtil.ES_INDEX_NAME).id(g.getGoodsId()).source(JSONObject.toJSONString(g), XContentType.JSON));
+                bulkRequest.add(new IndexRequest(DomainUrlUtil.ES_INDEX_NAME + "_" + webSite).id(g.getGoodsId()).source(JSONObject.toJSONString(g), XContentType.JSON));
             }
             response = client.bulk(bulkRequest, RequestOptions.DEFAULT);
         } catch (Exception e) {
@@ -363,13 +382,13 @@ public class ESGoodsModel {
      * @param goodsList
      * @throws IOException
      */
-    private void deleteByQuery(String url, Integer port, List<Goods> goodsList) throws IOException {
+    private void deleteByQuery(String url, Integer port, List<Goods> goodsList, String webSite) throws IOException {
         RestHighLevelClient client = null;
         try {
             client = getESClient();
             BulkRequest bulkRequest = new BulkRequest();
             for (Goods g : goodsList) {
-                bulkRequest.add(new DeleteRequest(DomainUrlUtil.ES_INDEX_NAME, g.getGoodsId().toString()));
+                bulkRequest.add(new DeleteRequest(DomainUrlUtil.ES_INDEX_NAME + "_" + webSite, g.getGoodsId().toString()));
             }
             client.bulk(bulkRequest, RequestOptions.DEFAULT);
         } catch (Exception e) {
@@ -385,11 +404,12 @@ public class ESGoodsModel {
 
     /**
      * 查询满足条件的商品对应的店铺id
+     *
      * @param categoryId 分类id
-     * @param keyword 关键词
+     * @param keyword    关键词
      * @return 店铺id集合
      */
-    public Set<Long> searchStoreIdsByEs(Integer categoryId,String keyword){
+    public Set<Long> searchStoreIdsByEs(Integer categoryId, String keyword) {
         Set<Long> result = new HashSet<>();//返回数据
         RestHighLevelClient client = getESClient();//获取es客户端
         SearchRequest searchRequest = new SearchRequest(DomainUrlUtil.ES_INDEX_NAME);
@@ -397,24 +417,24 @@ public class ESGoodsModel {
         //构造查询条件
         BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
         SearchConditionDTO qc = new SearchConditionDTO();
-        if (!StringUtil.isNullOrZero(categoryId)){
+        if (!StringUtil.isNullOrZero(categoryId)) {
             qc.setCategoryIds(categoryId + "");
             boolQueryBuilder.must(this.searchIndexAssembling4cate(qc));
         }
-        if (!StringUtils.isEmpty(keyword)){
+        if (!StringUtils.isEmpty(keyword)) {
             qc.setKeyword(keyword);
             boolQueryBuilder.must(this.searchIndexAssembling4keyword(qc));
         }
         SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
         searchSourceBuilder.size(0);
         //聚合查询,将所有符合条件的店铺id放入list
-        searchSourceBuilder.aggregation(AggregationBuilders.filter("query",boolQueryBuilder)
+        searchSourceBuilder.aggregation(AggregationBuilders.filter("query", boolQueryBuilder)
                 .subAggregation(AggregationBuilders.terms("list").field(SearchProductDTO.STORE_ID_ + ".keyword").size(1000000)));
         searchRequest.source(searchSourceBuilder);
         try {
             //解析查询结果,拿到店铺id list
             SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
-            ParsedFilter filter = (ParsedFilter)searchResponse.getAggregations().asList().get(0);//过滤后的结果集
+            ParsedFilter filter = (ParsedFilter) searchResponse.getAggregations().asList().get(0);//过滤后的结果集
             ParsedStringTerms terms = (ParsedStringTerms) filter.getAggregations().asList().get(0);//聚合属性值id的结果集
             terms.getBuckets().forEach(buckets -> {
                 String key = (String) buckets.getKey();
@@ -440,7 +460,7 @@ public class ESGoodsModel {
      * @param keyword    关键词
      * @return 店铺商品
      */
-    public List<SearchProductDTO> getStoreGoodsList(String storeIds,Integer categoryId,String keyword){
+    public List<SearchProductDTO> getStoreGoodsList(String storeIds, Integer categoryId, String keyword) {
         List<SearchProductDTO> result = new ArrayList<>();
         RestHighLevelClient client = getESClient();
         SearchRequest searchRequest = new SearchRequest(DomainUrlUtil.ES_INDEX_NAME);
@@ -450,14 +470,14 @@ public class ESGoodsModel {
         //构造查询条件
         BoolQueryBuilder storeQuery = QueryBuilders.boolQuery();
         for (String storeId : storeIds.split(",")) {
-            storeQuery.should(QueryBuilders.matchQuery(SearchProductDTO.STORE_ID_,storeId));
+            storeQuery.should(QueryBuilders.matchQuery(SearchProductDTO.STORE_ID_, storeId));
         }
         boolQueryBuilder.must(storeQuery);
-        if (!StringUtil.isNullOrZero(categoryId)){
+        if (!StringUtil.isNullOrZero(categoryId)) {
             qc.setCategoryIds(categoryId + "");
             boolQueryBuilder.must(this.searchIndexAssembling4cate(qc));
         }
-        if (!StringUtils.isEmpty(keyword)){
+        if (!StringUtils.isEmpty(keyword)) {
             qc.setKeyword(keyword);
             boolQueryBuilder.must(this.searchIndexAssembling4keyword(qc));
         }
@@ -469,7 +489,7 @@ public class ESGoodsModel {
             SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
             SearchHits hits = searchResponse.getHits();
             for (SearchHit hit : hits.getHits()) {
-                result.add(JSON.parseObject(hit.getSourceAsString(),SearchProductDTO.class));
+                result.add(JSON.parseObject(hit.getSourceAsString(), SearchProductDTO.class));
             }
         } catch (Exception e) {
             log.error("es连接异常:", e);
@@ -486,6 +506,7 @@ public class ESGoodsModel {
     /**
      * 获取默认三级分类id
      * 获取规则:按条件查询前500条数据中,三级分类最多的即为默认分类
+     *
      * @param qc 查询条件
      * @return 默认三级分类id
      */
@@ -495,7 +516,7 @@ public class ESGoodsModel {
         SearchSourceBuilder searchSourceBuilder = this.getCountSearchSourceBuilder(qc);
         //查询前500条符合条件的记录,聚合获取条数最多的三级分类id
         searchSourceBuilder.size(500);
-        searchSourceBuilder.aggregation(AggregationBuilders.terms("list").field(SearchProductDTO.CATEGORY_ID3_+".keyword"));
+        searchSourceBuilder.aggregation(AggregationBuilders.terms("list").field(SearchProductDTO.CATEGORY_ID3_ + ".keyword"));
         searchRequest.source(searchSourceBuilder);
         try {
             SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

+ 3 - 0
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/model/goods/GoodsExtendModel.java

@@ -127,4 +127,7 @@ public class GoodsExtendModel {
     }
 
 
+    public List<GoodsExtend> listByExample(GoodsExtendExample goodsExtendExample) {
+        return goodsExtendReadMapper.listResByExample(goodsExtendExample);
+    }
 }

+ 24 - 8
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/model/member/advich/MemberEnquiryModel.java

@@ -482,13 +482,15 @@ public class MemberEnquiryModel {
      * @param isStoreAdmin
      * @param vendorId
      * @param validStatus
+     * @param webSite
+     * @param phone
      * @param pager
      * @return
      */
-    public List<MemberEnquiry> getEnquiryListByPage(String name, String email, Long storeId, String isStoreAdmin, Long vendorId, Integer validStatus,String webSite, PagerInfo pager) {
+    public List<MemberEnquiry> getEnquiryListByPage(String name, String email, Long storeId, String isStoreAdmin, Long vendorId, Integer validStatus,String webSite,String phone, PagerInfo pager) {
         List<MemberEnquiry> enquiryList = null;
         if (pager != null) {
-            enquiryList = memberEnquiryReadMapper.enquiryListPage(name, email, storeId, isStoreAdmin, vendorId, validStatus,webSite, pager.getStart(), pager.getPageSize());
+            enquiryList = memberEnquiryReadMapper.enquiryListPage(name, email, storeId, isStoreAdmin, vendorId, validStatus, webSite, phone, pager.getStart(), pager.getPageSize());
         }
         return enquiryList;
     }
@@ -502,10 +504,12 @@ public class MemberEnquiryModel {
      * @param isStoreAdmin
      * @param vendorId
      * @param validStatus
+     * @param webSite
+     * @param phone
      * @return
      */
-    public Integer enquiryListPageCount(String name, String email, Long storeId, String isStoreAdmin, Long vendorId, Integer validStatus,String webSite) {
-        return memberEnquiryReadMapper.enquiryListPageCount(name, email, storeId, isStoreAdmin, vendorId, validStatus,webSite);
+    public Integer enquiryListPageCount(String name, String email, Long storeId, String isStoreAdmin, Long vendorId, Integer validStatus,String webSite,String phone) {
+        return memberEnquiryReadMapper.enquiryListPageCount(name, email, storeId, isStoreAdmin, vendorId, validStatus, webSite, phone);
     }
 
     /**
@@ -513,12 +517,18 @@ public class MemberEnquiryModel {
      *
      * @param name  查询条件信息
      * @param email 查询条件信息
+     * @param storeId
+     * @param isSupAdmin
+     * @param sysAdminId
+     * @param validStatus
+     * @param webSite
+     * @param phone
      * @param pager 分页信息
      */
-    public List<MemberEnquiry> getEnquiryAdminListByPage(String name, String email, String isSupAdmin, Integer sysAdminId, Integer validStatus, PagerInfo pager, Long storeId, String webSite) {
+    public List<MemberEnquiry> getEnquiryAdminListByPage(String name, String email, String isSupAdmin, Integer sysAdminId, Integer validStatus, PagerInfo pager, Long storeId, String webSite,String phone) {
         List<MemberEnquiry> enquiryList = null;
         if (pager != null) {
-            enquiryList = memberEnquiryReadMapper.enquiryAdminListPage(name, email, isSupAdmin, sysAdminId, validStatus, pager.getStart(), pager.getPageSize(), storeId, webSite);
+            enquiryList = memberEnquiryReadMapper.enquiryAdminListPage(name, email, isSupAdmin, sysAdminId, validStatus, pager.getStart(), pager.getPageSize(), storeId, webSite,phone);
         }
         return enquiryList;
     }
@@ -528,10 +538,16 @@ public class MemberEnquiryModel {
      *
      * @param name  查询条件信息
      * @param email 查询条件信息
+     * @param isSupAdmin
+     * @param sysAdminId
+     * @param validStatus
+     * @param storeId
+     * @param webSite
+     * @param phone
      * @return 购物车列表
      */
-    public Integer enquiryAdminListPageCount(String name, String email, String isSupAdmin, Integer sysAdminId, Integer validStatus, Long storeId, String webSite) {
-        return memberEnquiryReadMapper.enquiryAdminListPageCount(name, email, isSupAdmin, sysAdminId, validStatus, storeId, webSite);
+    public Integer enquiryAdminListPageCount(String name, String email, String isSupAdmin, Integer sysAdminId, Integer validStatus, Long storeId, String webSite,String phone) {
+        return memberEnquiryReadMapper.enquiryAdminListPageCount(name, email, isSupAdmin, sysAdminId, validStatus, storeId, webSite, phone);
     }
 
     /**

+ 2 - 2
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/model/member/advich/MemberRegisterActiveModel.java

@@ -339,7 +339,7 @@ public class MemberRegisterActiveModel {
         // 阿里云发送
         Integer sendSmsType = 3;
         code.setSmsType(SMSConst.SMS_TYPE_1);
-        String templateCode = stringRedisTemplate.opsForValue().get("notification_sms_ali_register_success_sms_template");
+        String templateCode = stringRedisTemplate.opsForValue().get("notification_sms_ali_register_sms_template");
         sendSms(mobile, code, sendSmsType, templateCode, "register");
     }
 
@@ -523,7 +523,7 @@ public class MemberRegisterActiveModel {
         // 阿里云发送
         Integer sendSmsType = 3;
         code.setSmsType(SMSConst.SMS_TYPE_4);
-        String templateCode = stringRedisTemplate.opsForValue().get("notification_sms_ali_register_sms_template");
+        String templateCode = stringRedisTemplate.opsForValue().get("notification_sms_ali_register_success_sms_template");
         sendSms(mobile, code, sendSmsType, templateCode, "success");
     }
 }

+ 1 - 1
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/model/seller/SellerStoreCompanyShowModel.java

@@ -81,7 +81,7 @@ public class SellerStoreCompanyShowModel {
 
         //新增入库
         StoreCompanyShowList storeCompanyShowList = new StoreCompanyShowList();
-        storeCompanyShowList.setWebSite(storeCompanyShowList.getWebSite());
+        storeCompanyShowList.setWebSite(storeCompanyShowListAddDTO.getWebSite());
         storeCompanyShowList.setStoreId(vendor.getStoreId());
         storeCompanyShowList.setName(storeCompanyShowListAddDTO.getName());
         storeCompanyShowList.setPath(storeCompanyShowListAddDTO.getPath());

+ 13 - 0
xinkeaboard-server/b2b2c-web/src/main/resources/application-dev.yml

@@ -53,3 +53,16 @@ geoip:
   static:
     city:
       mmdb: /data/GeoLite2/GeoLite2-City.mmdb
+
+
+#外部接口
+analysis:
+  translateAddress: http://54.46.9.88:8007
+  loginUser: metaljacket@meshinfo.cn
+  password: d088821c1d6863ec
+  searchVolume: https://api.dataforseo.com/v3/keywords_data/google/search_volume/live
+  keywordsForSite: https://api.dataforseo.com/v3/keywords_data/google_ads/keywords_for_site/live
+  KeywordForSuggestions: https://api.dataforseo.com/v3/dataforseo_labs/google/keyword_suggestions/live
+  rankedKeywords: https://api.dataforseo.com/v3/dataforseo_labs/google/ranked_keywords/live
+  historicalTraffic: https://api.dataforseo.com/v3/dataforseo_labs/google/historical_bulk_traffic_estimation/live
+  modelName: gemini-2.5-flash

+ 1 - 0
xinkeaboard-server/b2b2c-web/src/main/resources/application.yml

@@ -45,6 +45,7 @@ secure:
       - "/v3/system/seller/setting/getSiteSettingList"
       - "/v3/system/seller/setting/getBusinessSettingList"
       - "/openapi/**"
+      - "/analysis/**"
     #      - "/v3/seller/seller/enquiry/sendMsgStr"
     login-urls: #登录接口
       - "/v3/frontLogin/**"

+ 4 - 1
xinkeaboard-server/b2b2c-web/src/main/resources/mapper/read/goods/GoodsBindRankReadMapper.xml

@@ -181,7 +181,10 @@
        	r.sort AS sort,
        	r.create_time AS createTime
     FROM `goods_bind_rank` b, goods_rank r
-    WHERE b.goods_id = #{example.goodsId} AND b.rank_id = r.rank_id AND r.state = 1
+    WHERE b.rank_id = r.rank_id AND r.state = 1
+    <if test="example.goodsId != null">
+      AND b.goods_id = #{example.goodsId}
+    </if>
     ORDER BY b.goods_rank ASC, r.sort ASC, r.create_time DESC
   </select>
 </mapper>

+ 5 - 0
xinkeaboard-server/b2b2c-web/src/main/resources/mapper/read/goods/GoodsExtendReadMapper.xml

@@ -225,4 +225,9 @@
     </choose>
     <include refid="limit" />
   </select>
+  <select id="listResByExample" resultMap="resultMap">
+    select goods_id, click_number, follow_number
+    from goods_extend
+    ORDER BY `extend_id` DESC
+  </select>
 </mapper>

+ 12 - 0
xinkeaboard-server/b2b2c-web/src/main/resources/mapper/read/member/MemberEnquiryReadMapper.xml

@@ -214,6 +214,9 @@
         <if test="webSite != null">
             AND t1.`web_site` = #{webSite}
         </if>
+        <if test="phone != null">
+            AND t1.`phone` like concat('%',#{phone},'%')
+        </if>
         order by t1.id desc
     </select>
 
@@ -238,6 +241,9 @@
         <if test="webSite != null">
             AND t1.`web_site` = #{webSite}
         </if>
+        <if test="phone != null">
+            AND t1.`phone` like concat('%',#{phone},'%')
+        </if>
         order by t1.id desc
         <include refid="limit"/>
     </select>
@@ -263,6 +269,9 @@
         <if test="webSite != null">
             AND t1.`web_site` = #{webSite}
         </if>
+        <if test="phone != null">
+            AND t1.`phone` like concat('%',#{phone},'%')
+        </if>
         order by t1.id desc
     </select>
 
@@ -300,6 +309,9 @@
         <if test="webSite != null">
             AND t1.`web_site` = #{webSite}
         </if>
+        <if test="phone != null">
+            AND t1.`phone` like concat('%',#{phone},'%')
+        </if>
         order by t1.id desc
         <include refid="limit"/>
     </select>

+ 13 - 1
xinkeaboard-server/doc/DDL/update.sql

@@ -274,6 +274,10 @@ VALUES(null, "国外站门户", 4, 1, 1, now(), now(), null),(null, "国内站
 UPDATE store_cms_article_category SET is_show = 0 WHERE category_name='PC商城';
 
 
+ALTER TABLE store_cms_article ADD COLUMN web_site TINYINT NOT NULL DEFAULT 1 COMMENT '站点 1:海外门户 2:国内分销门户' AFTER article_id;
+
+
+
 DROP TABLE IF EXISTS `sys_pc_first_adv`;
 CREATE TABLE `sys_pc_first_adv`
 (
@@ -323,8 +327,16 @@ ALTER TABLE sys_search_log ADD COLUMN web_site TINYINT NOT NULL DEFAULT 1 COMMEN
 
 ALTER TABLE goods_search_words ADD COLUMN web_site TINYINT NOT NULL DEFAULT 1 COMMENT '站点 1:国外站 2:国内站' AFTER words_id;
 
+INSERT INTO sys_setting (name, title, value, description,type)
+SELECT CONCAT(name, '_2') AS name,
+       title,
+       value,
+       description,
+       type
+FROM sys_setting
+WHERE name = 'es_index_update_time';
 
-
+CREATE INDEX idx_goods_click_follow ON goods_extend (goods_id, click_number, follow_number)
 
 
 

+ 1 - 0
xinkeaboard-server/pom.xml

@@ -29,6 +29,7 @@
         <module>b2b2c-config-starter</module>
         <module>smartid</module>
         <module>b2b2c-captcha</module>
+        <module>b2b2c-investment</module>
     </modules>
 
 </project>