Browse Source

Merge remote-tracking branch 'origin/master'

Gaosheng 1 ngày trước cách đây
mục cha
commit
68d1c0f5f9

+ 7 - 0
xinkeaboard-seller/config/router.config.js

@@ -315,6 +315,13 @@ export default [
         name: 'enquiry_receive_mail_setting',
         component: './order/enquiry/receive_mail_setting',
       },
+      //订单管理
+      {
+        path: '/order/order',
+        icon: 'setting',
+        name: 'order',
+        component: './order/enquiry/order',
+      },
       //店铺设置
       {
         path: '/store/setting',

+ 1 - 0
xinkeaboard-seller/src/locales/zh-CN/menu.js

@@ -21,6 +21,7 @@ export default {
   'menu.order_print_setting': '打印机设置',
   'menu.order_enquiry_lists': '询盘管理',
   'menu.enquiry_receive_mail_setting': '询盘邮箱设置',
+  'menu.order': '订单管理',
   'menu.order_order_lists': '订单列表',
   'menu.spell_group__order_lists': '拼团订单',
   'menu.order_order_deliver': '订单发货',

+ 1 - 1
xinkeaboard-seller/src/pages/User/Login.js

@@ -170,7 +170,7 @@ export default class LoginPage extends Component {
             {
               setLocalStorageTime();
             }
-            localStorage.setItem('user_info', JSON.stringify({ user_name: res.data.vendorName, vendorMobile: res.data.vendorMobile }));
+            localStorage.setItem('user_info', JSON.stringify({ user_name: res.data.vendorName, vendorMobile: res.data.vendorMobile ,url_9710:res.data.storeUrlBy9710,url_9810:res.data.storeUrlBy9810}));
             if (res.state == 267) {
               //登录的时候初始化入驻状态
               if (res.data.applyState == 0) {

+ 22 - 0
xinkeaboard-seller/src/pages/order/enquiry/order.js

@@ -0,0 +1,22 @@
+import React from 'react';
+
+let userInfo = JSON.parse(localStorage.user_info);
+const userName = userInfo.user_name;
+const url9710 = userInfo.url_9710;
+const src = `${url9710}&username=${userName}`;
+const BasicIframe = () => {
+  return (
+    <div style={{ width: '100%', height: '100%' }}>
+      <iframe
+        src={url9710}
+        title="Example Page"
+        width="100%"
+        height="100%"
+        frameBorder="0"
+        allowFullScreen
+      />
+    </div>
+  );
+};
+
+export default BasicIframe;

+ 14 - 0
xinkeaboard-server/b2b2c-core/pom.xml

@@ -189,6 +189,20 @@
             <artifactId>geoip2</artifactId>
             <version>2.12.0</version>
         </dependency>
+
+        <!-- Apache HttpClient 核心库 -->
+        <dependency>
+            <groupId>org.apache.httpcomponents.client5</groupId>
+            <artifactId>httpclient5</artifactId>
+            <version>5.3</version>
+        </dependency>
+
+        <!-- 处理 multipart 表单数据的扩展库 -->
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpmime</artifactId>
+            <version>4.5.13</version>
+        </dependency>
     </dependencies>
 
     <repositories>

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

@@ -1,5 +1,7 @@
 package com.slodon.b2b2c.core.util;
 
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.http.HttpRequest;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpStatus;
 import org.apache.http.NameValuePair;
@@ -12,16 +14,21 @@ import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.StringEntity;
+import org.apache.http.entity.mime.content.FileBody;
+import org.apache.http.entity.mime.content.StringBody;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.message.BasicNameValuePair;
 import org.apache.http.util.EntityUtils;
 
+import java.io.File;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.nio.charset.UnsupportedCharsetException;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Map;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
 
 /**
  * http请求工具类
@@ -331,4 +338,28 @@ public class HttpClientUtil {
         return null;
     }
 
+
+
+    public static String httpPost(String url, Map<String, Object> paramMap, HashMap<String, String> headers){
+        return HttpRequest.post(url)
+                .headerMap(headers,false)
+                .form(paramMap)
+                .execute()
+                .body();
+    }
+
+    public static String httpDelete(String url, HashMap<String, String> headers){
+        return HttpRequest.delete(url)
+                .headerMap(headers,false)
+                .execute()
+                .body();
+    }
+
+    public static String httpGet(String url,HashMap<String, String> headers){
+        return HttpRequest.get(url)
+                .headerMap(headers,false)
+                .execute()
+                .body();
+    }
+
 }

+ 2 - 2
xinkeaboard-server/b2b2c-entity/src/main/java/com/slodon/b2b2c/seller/pojo/Vendor.java

@@ -62,9 +62,9 @@ public class Vendor implements Serializable {
 
     private String statusMsg;
 
-    @ApiModelProperty("获取商店9710模块url")
+    @ApiModelProperty("用户9710地址")
     private String storeUrlBy9710;
 
-    @ApiModelProperty("获取商店9810模块url")
+    @ApiModelProperty("用户9810地址")
     private String storeUrlBy9810;
 }

+ 19 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/config/DifyConfig.java

@@ -0,0 +1,19 @@
+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/12 9:25
+ */
+@Component
+@ConfigurationProperties(prefix = "dify")
+@Data
+public class DifyConfig {
+    private String apiKey;
+    private String difyRoute;
+}

+ 32 - 1
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/constant/AnalysisConst.java → xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/constant/InvestmentConst.java

@@ -6,7 +6,7 @@ package com.slodon.b2b2c.investment.constant;
  * @description: TODO
  * @date 2025/8/5 15:33
  */
-public class AnalysisConst {
+public class InvestmentConst {
     /**
      * 默认固定线程数
      */
@@ -20,6 +20,7 @@ public class AnalysisConst {
     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 NUM_ONE_THOUSAND = 1000;
     public static final int NEGATIVE_ONE = -1;
     /**
      * 线程池存活时间
@@ -52,4 +53,34 @@ public class AnalysisConst {
             "\n" +
             "## 参考资料";
     public static final String FIRST_MARKER = "## 4. 引用";
+
+    // dify 配置
+    public static final String BEARER = "Bearer ";
+    public static final String NAME = "name";
+    public static final String INDEXING_TECHNIQUE = "indexing_technique";
+    public static final String HIGH_QUALITY = "high_quality";
+    public static final String MODE = "mode";
+    public static final String AUTOMATIC = "automatic";
+    public static final String PROCESS_RULE = "process_rule";
+    public static final String CREATE_BY_TEXT = "/document/create-by-text";
+    public static final String DOCUMENT_ID = "document.id";
+    public static final String DOCUMENTS = "/documents/";
+    public static final String UPDATE_BY_TEXT = "/update-by-text";
+    public static final String ID = "id";
+    public static final String REMOVE_EXTRA_SPACES = "remove_extra_spaces";
+    public static final String ENABLED = "enabled";
+    public static final String REMOVE_URLS_EMAILS = "remove_urls_emails";
+    public static final String SEPARATOR = "separator";
+    public static final String SEPARATOR_VALUE = "###";
+    public static final String MAX_TOKENS = "max_tokens";
+    public static final String PRE_PROCESSING_RULES = "pre_processing_rules";
+    public static final String SEGMENTATION = "segmentation";
+    public static final String RULES = "rules";
+    public static final String CUSTOM = "custom";
+    public static final String CREATE_BY_FILE = "/document/create-by-file";
+    public static final String UPDATE_BY_FILE = "/update-by-file";
+    public static final String FILE = "file";
+    public static final String DATA = "data";
+
+    public static final String DELETE_SUCCESS = "204\n";
 }

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

@@ -10,7 +10,7 @@ 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 com.slodon.b2b2c.investment.constant.InvestmentConst;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Component;
@@ -48,10 +48,10 @@ public class AnalysisModel {
  */
 public List<String> translateProduct(String originalText) throws Exception {
     HashMap<String, String> headers = new HashMap<>();
-    headers.put(AnalysisConst.CONTENT_TYPE, AnalysisConst.APPLICATION_JSON);
+    headers.put(InvestmentConst.CONTENT_TYPE, InvestmentConst.APPLICATION_JSON);
     JSONObject param = new JSONObject();
-    param.set(AnalysisConst.TEXT, originalText);
-    param.set(AnalysisConst.MODEL_NAME, analysisConfig.getModelName());
+    param.set(InvestmentConst.TEXT, originalText);
+    param.set(InvestmentConst.MODEL_NAME, analysisConfig.getModelName());
     String result;
     try {
         result = HttpClientUtil.httpPost(analysisConfig.getTranslateAddress() + "/api/translate", param.toString(), headers);
@@ -65,9 +65,9 @@ public List<String> translateProduct(String originalText) throws Exception {
         throw new Exception("翻译结果为空");
     }
     int start = text.indexOf("[");
-    int end = text.lastIndexOf("]") + AnalysisConst.NUM_ONE;
+    int end = text.lastIndexOf("]") + InvestmentConst.NUM_ONE;
     String jsonString = "";
-    if (start != AnalysisConst.NEGATIVE_ONE && end != AnalysisConst.NEGATIVE_ONE && start < end) {
+    if (start != InvestmentConst.NEGATIVE_ONE && end != InvestmentConst.NEGATIVE_ONE && start < end) {
         jsonString = text.substring(start, end);
     } else {
         throw new Exception("未找到翻译结果");
@@ -83,21 +83,21 @@ public HashMap<String,String> getCredential(){
             .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);
+    headers.put(InvestmentConst.CONTENT_TYPE, InvestmentConst.APPLICATION_JSON);
+    headers.put(InvestmentConst.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,
+            InvestmentConst.DEFAULT_RUN_THREAD_NUM,
+            InvestmentConst.DEFAULT_RUN_THREAD_NUM,
+            InvestmentConst.KEEP_ALIVE_TIME,
             TimeUnit.MILLISECONDS,
-            new LinkedBlockingQueue<>(AnalysisConst.WORK_QUEUE),
+            new LinkedBlockingQueue<>(InvestmentConst.WORK_QUEUE),
             new ThreadFactory() {
-                private int count = AnalysisConst.NUM_ZERO;
+                private int count = InvestmentConst.NUM_ZERO;
                 @Override
                 public Thread newThread(Runnable r) {
                     Thread thread = new Thread(r);
@@ -112,7 +112,7 @@ private ThreadPoolExecutor createThreadPool() {
     private void shutdownThreadPool(ThreadPoolExecutor executor) {
         executor.shutdown();
         try {
-            if (!executor.awaitTermination(AnalysisConst.NUM_TEN, TimeUnit.SECONDS)) {
+            if (!executor.awaitTermination(InvestmentConst.NUM_TEN, TimeUnit.SECONDS)) {
                 executor.shutdownNow();
             }
         } catch (InterruptedException e) {
@@ -137,19 +137,19 @@ public KeyWordPartVO searchVolume(HashMap<String,String> header,String keywords,
     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);
+    payloadItem.set(InvestmentConst.KEYWORDS, keywordsArray);
+    payloadItem.set(InvestmentConst.LANGUAGE_NAME, InvestmentConst.ENGLISH);
+    payloadItem.set(InvestmentConst.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){
+    if(tasksError==null||tasksError> InvestmentConst.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);
+    Integer cp = competition==null?null:(int)Math.round(competition * InvestmentConst.NUM_ONE_HUNDRED);
     keyWordPartVO.setMonthlySearchesBO(bo);
     keyWordPartVO.setCompetition(cp);
     return keyWordPartVO;
@@ -170,18 +170,18 @@ public SuggestionVO KeywordForSuggestions(HashMap<String,String> header, String
     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(InvestmentConst.KEYWORD, keyword);
+    payloadItem.set(InvestmentConst.LANGUAGE_NAME, InvestmentConst.ENGLISH);
+    payloadItem.set(InvestmentConst.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);
+    payloadItem.set(InvestmentConst.LIMIT, InvestmentConst.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){
+    if(tasksError==null||tasksError> InvestmentConst.NUM_ZERO){
         throw new RuntimeException("接口5查询推荐数据 任务失败");
     }
     JSONArray jsonArray = postObject.getByPath("tasks[0].result[0].items", JSONArray.class);
@@ -192,10 +192,10 @@ public SuggestionVO KeywordForSuggestions(HashMap<String,String> header, String
     for (Object o : jsonArray) {
         RelatedInfoBO bo = new RelatedInfoBO();
         JSONObject obj = (JSONObject) o;
-        bo.setKeyword(obj.getByPath(AnalysisConst.KEYWORD, String.class));
+        bo.setKeyword(obj.getByPath(InvestmentConst.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));
+        bo.setCompetition(competition==null?null:(int)Math.round(competition * InvestmentConst.NUM_ONE_HUNDRED));
         relatedInfoBOList.add(bo);
     }
     suggestionVO.setRelatedInfoBOList(relatedInfoBOList);
@@ -209,7 +209,7 @@ public SuggestionVO KeywordForSuggestions(HashMap<String,String> header, String
         String websites = dto.getCompetitorWebsite();
         String[] competitorWebsites = websites.split(",");
         RivalPartVO vo = new RivalPartVO();
-        if(competitorWebsites.length== AnalysisConst.NUM_ZERO){
+        if(competitorWebsites.length== InvestmentConst.NUM_ZERO){
             throw new Exception("竞品网站地址不正确");
         }
         List<CompetitorBO> competitorBOS = new ArrayList<>();
@@ -269,14 +269,14 @@ public SuggestionVO KeywordForSuggestions(HashMap<String,String> header, String
     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);
+        payloadItem.set(InvestmentConst.TARGET, website);
+        payloadItem.set(InvestmentConst.LANGUAGE_NAME, InvestmentConst.ENGLISH);
+        payloadItem.set(InvestmentConst.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){
+        if(tasksError==null||tasksError> InvestmentConst.NUM_ZERO){
             throw new RuntimeException("接口7查询 关键词排名 任务失败");
         }
         JSONArray items = postObject.getByPath("tasks[0].result[0].items", JSONArray.class);
@@ -289,9 +289,9 @@ public SuggestionVO KeywordForSuggestions(HashMap<String,String> header, String
             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);
+            Integer dp = competition==null?null:(int)Math.round(competition * InvestmentConst.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;
+            Double cpcFormat=cpc==null?null:Math.round(cpc * InvestmentConst.NUM_ONE_HUNDRED) / InvestmentConst.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);
@@ -316,21 +316,21 @@ public SuggestionVO KeywordForSuggestions(HashMap<String,String> header, String
         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);
+                StringUtils.removeStart(website, InvestmentConst.HTTPS),
+                    InvestmentConst.HTTP),
+                InvestmentConst.WWW);
+        int comIndex = keyword.indexOf(InvestmentConst.COM);
+        if (comIndex != -InvestmentConst.NEGATIVE_ONE) {
+            keyword =  keyword.substring(InvestmentConst.NUM_ZERO, comIndex+ InvestmentConst.NUM_FOUR);
         }
         targets.add(keyword);
-        payloadItem.set(AnalysisConst.TARGETS,targets);
-        payloadItem.set(AnalysisConst.LANGUAGE_NAME, AnalysisConst.ENGLISH);
-        payloadItem.set(AnalysisConst.LOCATION_NAME, locationName);
+        payloadItem.set(InvestmentConst.TARGETS,targets);
+        payloadItem.set(InvestmentConst.LANGUAGE_NAME, InvestmentConst.ENGLISH);
+        payloadItem.set(InvestmentConst.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);
+        LocalDate currentMonthFirstDay = currentDate.withDayOfMonth(InvestmentConst.NUM_ONE);
+        LocalDate lastYearSameMonthFirstDay = currentDate.minusYears(InvestmentConst.NUM_ONE).plusMonths(InvestmentConst.NUM_ONE).withDayOfMonth(InvestmentConst.NUM_ONE);
         DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE;
         payloadItem.set("date_from", lastYearSameMonthFirstDay.format(formatter));
         payloadItem.set("date_to", currentMonthFirstDay.format(formatter));
@@ -344,7 +344,7 @@ public SuggestionVO KeywordForSuggestions(HashMap<String,String> header, String
         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){
+        if(tasksError==null||tasksError> InvestmentConst.NUM_ZERO){
             throw new RuntimeException("接口8查询 历史流量 任务失败");
         }
         List<TrafficBO> list = new ArrayList<>();
@@ -380,15 +380,15 @@ public SuggestionVO KeywordForSuggestions(HashMap<String,String> header, String
     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);
+        payloadItem.set(InvestmentConst.TARGET, website);
+        payloadItem.set(InvestmentConst.LANGUAGE_NAME, InvestmentConst.ENGLISH);
+        payloadItem.set(InvestmentConst.LOCATION_NAME, locationName);
+        payloadItem.set(InvestmentConst.LIMIT, InvestmentConst.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){
+        if(tasksError==null||tasksError> InvestmentConst.NUM_ZERO){
             throw new RuntimeException("接口3查询 keywordsForSite 任务失败");
         }
         List<RecommendationBO> list = new ArrayList<>();
@@ -396,14 +396,14 @@ public SuggestionVO KeywordForSuggestions(HashMap<String,String> header, String
         if(results==null){
             return list;
         }
-        int total = Math.min(results.size(), AnalysisConst.NUM_FIFTY);
-        for(int i = AnalysisConst.NUM_ZERO; i<total; i++){
+        int total = Math.min(results.size(), InvestmentConst.NUM_FIFTY);
+        for(int i = InvestmentConst.NUM_ZERO; i<total; i++){
             JSONObject result = (JSONObject) results.get(i);
             RecommendationBO bo = new RecommendationBO();
-            bo.setKeywords(result.getByPath(AnalysisConst.KEYWORD,String.class));
+            bo.setKeywords(result.getByPath(InvestmentConst.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;
+            Double cpcFormat=cpc==null?null:Math.round(cpc * InvestmentConst.NUM_ONE_HUNDRED) / InvestmentConst.ONE_HUNDRED_DOUBLE;
             bo.setPrice(cpcFormat);
             list.add(bo);
         }
@@ -412,11 +412,11 @@ public SuggestionVO KeywordForSuggestions(HashMap<String,String> header, String
 
     public String qualitative(String keyword) throws Exception {
         HashMap<String, String> headers = new HashMap<>();
-        headers.put(AnalysisConst.CONTENT_TYPE, AnalysisConst.APPLICATION_JSON);
+        headers.put(InvestmentConst.CONTENT_TYPE, InvestmentConst.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("initial_search_query_count", InvestmentConst.NUM_THREE);
+        param.set("max_research_loops", InvestmentConst.NUM_THREE);
         param.set("reasoning_model", analysisConfig.getModelName());
         String result;
         try {
@@ -434,15 +434,15 @@ public SuggestionVO KeywordForSuggestions(HashMap<String,String> header, String
     }
 
     private String dealAnswer(String answer) {
-        answer = answer.replace(AnalysisConst.CHINESE, "");
+        answer = answer.replace(InvestmentConst.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) {
+        int startIndex = answer.indexOf (InvestmentConst.LAST_PART_MARKER);
+        if (startIndex != InvestmentConst.NEGATIVE_ONE) {
             return answer.substring (startIndex);
         } else {
             return "";
@@ -450,9 +450,9 @@ public SuggestionVO KeywordForSuggestions(HashMap<String,String> header, String
     }
 
     public String getFirstPart (String input) {
-        int markerIndex = input.indexOf (AnalysisConst.FIRST_MARKER);
-        if (markerIndex != AnalysisConst.NEGATIVE_ONE) {
-            return input.substring (AnalysisConst.NUM_ZERO, markerIndex);
+        int markerIndex = input.indexOf (InvestmentConst.FIRST_MARKER);
+        if (markerIndex != InvestmentConst.NEGATIVE_ONE) {
+            return input.substring (InvestmentConst.NUM_ZERO, markerIndex);
         } else {
             return input;
         }

+ 305 - 0
xinkeaboard-server/b2b2c-investment/src/main/java/com/slodon/b2b2c/investment/model/DifyModel.java

@@ -0,0 +1,305 @@
+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.config.DifyConfig;
+import com.slodon.b2b2c.investment.constant.InvestmentConst;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import javax.annotation.Resource;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.jacoco.agent.rt.internal_1f1cc91.core.runtime.AgentOptions.OutputMode.file;
+
+/**
+ * @author sunshihao
+ * @version 1.0
+ * @description: dify api调用
+ * @date 2025/8/14 11:56
+ */
+@Component
+@Slf4j
+public class DifyModel {
+
+
+    @Resource
+    private DifyConfig difyConfig;
+
+    /***
+     * @description: 获取请求头
+     * @author sunshihao
+     * @date: 2025/8/14 14:06
+     */
+    private HashMap<String,String> getCredential(){
+        String apiKey = difyConfig.getApiKey();
+        HashMap<String, String> headers = new HashMap<>();
+        headers.put(InvestmentConst.AUTHORIZATION, InvestmentConst.BEARER +apiKey);
+        headers.put(InvestmentConst.CONTENT_TYPE, InvestmentConst.APPLICATION_JSON);
+        return headers;
+    }
+
+    /***
+     * @description:  通过文本创建文档
+     * @param dataSetId 知识库id
+     * @param name 文件名
+     * @param text 文件内容
+     * @author sunshihao
+     * @date: 2025/8/14 14:06
+     */
+    public void createByText(String dataSetId, String name, String text) throws Exception {
+        HashMap<String, String> header = getCredential();
+        JSONObject payloadItem = getTextParam(name, text);
+        String url = difyConfig.getDifyRoute()+dataSetId+ InvestmentConst.CREATE_BY_TEXT;
+        String post = HttpClientUtil.httpPost(url, payloadItem.toString(),header);
+        JSONObject postObject = JSONUtil.parseObj(post);
+        String docId = postObject.getByPath(InvestmentConst.DOCUMENT_ID, String.class);
+        if(docId==null){
+            throw new Exception("根据文本创建文档失败");
+        }
+    }
+
+
+    /***
+     * @description: 通过文本更新文档
+     * @param dataSetId 知识库id
+     * @param documentId 原文档id
+     * @param name 文件名
+     * @param text 文件内容
+     * @return: void
+     * @author sunshihao
+     * @date: 2025/8/14 14:06
+     */
+    public void updateByText(String dataSetId, String documentId,String name, String text) throws Exception {
+        HashMap<String, String> header = getCredential();
+        JSONObject payloadItem = getTextParam(name, text);
+        String url = difyConfig.getDifyRoute()+dataSetId+ InvestmentConst.DOCUMENTS +documentId+ InvestmentConst.UPDATE_BY_TEXT;
+        String post = HttpClientUtil.httpPost(url, payloadItem.toString(),header);
+        JSONObject postObject = JSONUtil.parseObj(post);
+        String docId = postObject.getByPath(InvestmentConst.DOCUMENT_ID, String.class);
+        if(docId==null){
+            throw new Exception("根据文本修改文档失败");
+        }
+    }
+
+    /***
+     * @description: 获取文本参数
+     * @param name 文件名
+     * @param text 文件内容
+     * @return: cn.hutool.json.JSONObject
+     * @author sunshihao
+     * @date: 2025/8/14 14:07
+     */
+    private JSONObject getTextParam(String name, String text) {
+        JSONObject payloadItem = new JSONObject();
+        payloadItem.set(InvestmentConst.NAME, name);
+        payloadItem.set(InvestmentConst.TEXT, text);
+        payloadItem.set(InvestmentConst.INDEXING_TECHNIQUE, InvestmentConst.HIGH_QUALITY);
+        JSONObject mode = new JSONObject();
+        mode.set(InvestmentConst.MODE, InvestmentConst.AUTOMATIC);
+        payloadItem.set(InvestmentConst.PROCESS_RULE, mode);
+        return payloadItem;
+    }
+
+
+    /***
+     * @description:通过文件创建文档
+     * @param dataSetId 知识库id
+     * @param file 文件
+     * @return: void
+     * @author sunshihao
+     * @date: 2025/8/14 14:09
+     */
+    public void createByFile(String dataSetId,File file) throws Exception {
+        HashMap<String, String> header = getCredential();
+        JSONObject payloadItem = getFileParam();
+        String url = difyConfig.getDifyRoute()+dataSetId+ InvestmentConst.CREATE_BY_FILE;
+        Map<String, Object> paramMap = new HashMap<>();
+        paramMap.put(InvestmentConst.FILE, file);
+        paramMap.put(InvestmentConst.DATA, payloadItem);
+        String post = HttpClientUtil.httpPost(url, paramMap,header);
+        JSONObject postObject = JSONUtil.parseObj(post);
+        String docId = postObject.getByPath(InvestmentConst.DOCUMENT_ID, String.class);
+        if(docId==null){
+            throw new Exception("通过文件创建文档失败");
+        }
+    }
+
+
+    /***
+     * @description: 通过文件修改文档
+     * @param:
+     * @param dataSetId 知识库id
+     * @param documentId 原文件id
+     * @param name 修改后的文件名
+     * @param file 文件
+     * @return: void
+     * @author sunshihao
+     * @date: 2025/8/14 14:10
+     */
+    public void updateByFile(String dataSetId, String documentId, String name, File file) throws Exception {
+        HashMap<String, String> header = getCredential();
+        JSONObject payloadItem = getFileParam();
+        if(!StringUtils.isEmpty(name)){
+            payloadItem.set(InvestmentConst.NAME,name);
+        }
+        String url = difyConfig.getDifyRoute()+dataSetId+InvestmentConst.DOCUMENTS+documentId+ InvestmentConst.UPDATE_BY_FILE;
+        Map<String, Object> paramMap = new HashMap<>();
+        paramMap.put(InvestmentConst.FILE, file);
+        paramMap.put(InvestmentConst.DATA, payloadItem);
+        String post = HttpClientUtil.httpPost(url, paramMap,header);
+        JSONObject postObject = JSONUtil.parseObj(post);
+        String docId = postObject.getByPath(InvestmentConst.DOCUMENT_ID, String.class);
+        if(docId==null){
+            throw new Exception("通过文件修改文档失败");
+        }
+    }
+
+    /***
+     * @description:设置文件接口参数
+     * @return: cn.hutool.json.JSONObject
+     * @author sunshihao
+     * @date: 2025/8/14 14:11
+     */
+    private static JSONObject getFileParam() {
+        JSONObject payloadItem = new JSONObject();
+        payloadItem.set(InvestmentConst.INDEXING_TECHNIQUE, InvestmentConst.HIGH_QUALITY);
+        JSONObject rules = new JSONObject();
+        JSONArray preProcessingRules = new JSONArray();
+        JSONObject space = new JSONObject();
+        space.set(InvestmentConst.ID, InvestmentConst.REMOVE_EXTRA_SPACES);
+        space.set(InvestmentConst.ENABLED, false);
+        JSONObject emails = new JSONObject();
+        emails.set(InvestmentConst.ID, InvestmentConst.REMOVE_URLS_EMAILS);
+        emails.set(InvestmentConst.ENABLED, false);
+        preProcessingRules.add(space);
+        preProcessingRules.add(emails);
+        JSONObject segmentation = new JSONObject();
+        segmentation.set(InvestmentConst.SEPARATOR, InvestmentConst.SEPARATOR_VALUE);
+        segmentation.set(InvestmentConst.MAX_TOKENS, InvestmentConst.NUM_ONE_THOUSAND);
+        rules.set(InvestmentConst.PRE_PROCESSING_RULES, preProcessingRules);
+        rules.set(InvestmentConst.SEGMENTATION, segmentation);
+        JSONObject processRule = new JSONObject();
+        processRule.set(InvestmentConst.RULES, rules);
+        processRule.set(InvestmentConst.MODE, InvestmentConst.CUSTOM);
+        payloadItem.set(InvestmentConst.PROCESS_RULE, processRule);
+        return payloadItem;
+    }
+
+    /***
+     * @description:删除文档
+     * @param dataSetId 知识库id
+     * @param documentId  原文件id
+     * @return: void
+     * @author sunshihao
+     * @date: 2025/8/14 14:11
+     */
+    public void deleteDoc(String dataSetId, String documentId) throws Exception {
+        HashMap<String, String> header = getCredential();
+        String url = difyConfig.getDifyRoute()+dataSetId+InvestmentConst.DOCUMENTS+documentId;
+        String post = HttpClientUtil.httpDelete(url,header);
+        if(!InvestmentConst.DELETE_SUCCESS.equals(post)){
+            throw new Exception("删除文档失败");
+        }
+    }
+
+    /***
+     * @description: 查询知识库列表
+     * @param keyword 关键词
+     * @param tagIds 标签数组
+     * @param page 页码
+     * @author sunshihao
+     * @date: 2025/8/18 11:35
+     */
+    public List<String> datasets(String keyword, String[] tagIds, Integer page, List<String> list) throws Exception {
+        if (list == null) {
+            list = new ArrayList<>();
+        }
+        int currentPage = (page == null || page <= 0) ? 1 : page;
+        int limit = 100;
+        HashMap<String, String> header = getCredential();
+        String baseUrl = difyConfig.getDifyRoute();
+        while (true) {
+            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUrl)
+                    .queryParam("page", currentPage)
+                    .queryParam("limit", limit);
+
+            if (!StringUtils.isEmpty(keyword)) {
+                builder.queryParam("keyword", keyword);
+            }
+            if (tagIds != null && tagIds.length > 0) {
+                String tagIdsStr = String.join(",", tagIds);
+                builder.queryParam("tag_ids", tagIdsStr);
+            }
+            String url = builder.toUriString();
+            String response = HttpClientUtil.httpGet(url, header);
+            if (response == null) {
+                throw new Exception("HTTP请求返回空响应");
+            }
+            JSONObject postObject = JSONUtil.parseObj(response);
+            JSONArray dataArray = postObject.getByPath("data", JSONArray.class);
+            if (dataArray == null) {
+                throw new Exception("查询知识库失败:data字段为空");
+            }
+            for (Object o : dataArray) {
+                JSONObject obj = (JSONObject) o;
+                String id = obj.getByPath("id", String.class);
+                if (id != null) {
+                    list.add(id);
+                }
+            }
+            Integer total = postObject.getByPath("total", Integer.class);
+            if (total == null) {
+                throw new Exception("响应中缺少 total 字段");
+            }
+            if (list.size() >= total) {
+                break;
+            }
+            currentPage++;
+        }
+        return list;
+    }
+
+    /*** 
+     * @description: 查询知识库当中的文章列表
+     * @param datasetId 知识库id
+     * @param name 文章名称
+     * @return: java.lang.String 文章id
+     * @author sunshihao
+     * @date: 2025/8/18 13:44
+     */ 
+    public String documents(String datasetId,String name) throws Exception {
+        HashMap<String, String> header = getCredential();
+        String baseUrl = difyConfig.getDifyRoute()+datasetId+"/documents";
+        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUrl)
+                .queryParam("page", 1)
+                .queryParam("limit", 100);
+        if (!StringUtils.isEmpty(name)) {
+            builder.queryParam("keyword", name);
+        }
+        String url = builder.toUriString();
+        String response = HttpClientUtil.httpGet(url, header);
+        if (response == null) {
+            throw new Exception("HTTP请求返回空响应");
+        }
+        JSONObject postObject = JSONUtil.parseObj(response);
+        JSONArray dataArray = postObject.getByPath("data", JSONArray.class);
+        if (dataArray == null) {
+            throw new Exception("查询文章失败:data字段为空");
+        }
+        for (Object o : dataArray) {
+            JSONObject obj = (JSONObject) o;
+            return obj.getByPath("id", String.class);
+        }
+        return null;
+    }
+}

+ 2 - 0
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/controller/sso/seller/SellerAuthController.java

@@ -138,6 +138,8 @@ public class SellerAuthController {
         vo.setIsStoreAdmin(vendor.getIsStoreAdmin());
         vo.setVendorName(vendor.getVendorName());
         vo.setVendorMobile(vendor.getVendorMobile());
+        vo.setStoreUrlBy9710(vendor.getStoreUrlBy9710());
+        vo.setStoreUrlBy9810(vendor.getStoreUrlBy9810());
 
         vendor.setVendorPassword("");
         //构造存储对象

+ 6 - 0
xinkeaboard-server/b2b2c-web/src/main/java/com/slodon/b2b2c/vo/seller/VendorLoginVO.java

@@ -49,4 +49,10 @@ public class VendorLoginVO {
 
     @ApiModelProperty("用户手机号")
     private String vendorMobile;
+
+    @ApiModelProperty("用户9710地址")
+    private String storeUrlBy9710;
+
+    @ApiModelProperty("用户9810地址")
+    private String storeUrlBy9810;
 }

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

@@ -55,7 +55,7 @@ geoip:
       mmdb: /data/GeoLite2/GeoLite2-City.mmdb
 
 
-#外部接口
+#dataforseo外部接口
 analysis:
   translateAddress: http://54.46.9.88:8007
   loginUser: metaljacket@meshinfo.cn
@@ -66,6 +66,10 @@ analysis:
   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
+#dify
+dify:
+  apiKey: dataset-t2bq146uJwJj00kxVyfOOWua
+  difyRoute: http://52.42.176.27/v1/datasets/
 
 store:
   url: https://xinke.sutextech.com/api/get_store_urls/

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

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