Forráskód Böngészése

Merge remote-tracking branch 'origin/sit' into sit

刘云鑫 2 hónapja
szülő
commit
8772f00116

+ 35 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/StorePlatformRoleServiceImpl.java

@@ -11,9 +11,12 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
+import shop.alien.config.redis.BaseRedisService;
 import shop.alien.entity.store.StorePlatformRole;
+import shop.alien.entity.store.StoreUser;
 import shop.alien.entity.store.vo.StorePlatformRoleVo;
 import shop.alien.mapper.StorePlatformRoleMapper;
+import shop.alien.mapper.StoreUserMapper;
 import shop.alien.storeplatform.service.StorePlatformRoleMenuService;
 import shop.alien.storeplatform.service.StorePlatformRoleService;
 import shop.alien.storeplatform.service.StorePlatformUserRoleService;
@@ -36,6 +39,8 @@ public class StorePlatformRoleServiceImpl extends ServiceImpl<StorePlatformRoleM
     private final StorePlatformRoleMapper storePlatformRoleMapper;
     private final StorePlatformRoleMenuService storePlatformRoleMenuService;
     private final StorePlatformUserRoleService storePlatformUserRoleService;
+    private final StoreUserMapper storeUserMapper;
+    private final BaseRedisService baseRedisService;
 
     @Override
     public IPage<StorePlatformRole> getRolePage(int page, int size, Integer storeId, String roleName, String description, String status) {
@@ -273,6 +278,36 @@ public class StorePlatformRoleServiceImpl extends ServiceImpl<StorePlatformRoleM
                     return false;
                 }
             }
+            //角色被编辑 清除当前被编辑角色的账号的token
+            try {
+                // 获取该角色下的所有用户ID
+                Integer storeId = role.getStoreId() != null ? role.getStoreId() : originalRole.getStoreId();
+                List<Integer> userIds = storePlatformUserRoleService.getUserIdsByRoleId(role.getRoleId(), storeId);
+                if (userIds != null && !userIds.isEmpty()) {
+                    // 根据用户ID查询用户信息,获取手机号
+                    for (Integer userId : userIds) {
+                        StoreUser storeUser = storeUserMapper.selectById(userId);
+                        if (storeUser != null && storeUser.getPhone() != null) {
+                            // 删除Redis中的token,key格式:storePlatform_手机号
+                            String tokenKey = "store_" + storeUser.getPhone();
+                            String existingToken = baseRedisService.getString(tokenKey);
+                            if (existingToken != null) {
+                                baseRedisService.delete(tokenKey);
+                                log.info("清除角色编辑后的用户token成功,roleId={}, userId={}, phone={}, tokenKey={}", 
+                                        role.getRoleId(), userId, storeUser.getPhone(), tokenKey);
+                            } else {
+                                log.warn("用户token不存在或已过期,roleId={}, userId={}, phone={}, tokenKey={}", 
+                                        role.getRoleId(), userId, storeUser.getPhone(), tokenKey);
+                            }
+                        }
+                    }
+                } else {
+                    log.info("该角色下没有关联用户,无需清除token,roleId={}", role.getRoleId());
+                }
+            } catch (Exception e) {
+                log.error("清除角色编辑后的用户token失败,roleId={}, error={}", role.getRoleId(), e.getMessage(), e);
+                // 不清除token不影响角色更新,只记录错误日志
+            }
             log.info("成功更新角色权限,roleId={}, menuIds={}", role.getRoleId(), menuIds);
         }
 

+ 27 - 0
alien-store/src/main/java/shop/alien/store/controller/StoreOperationalStatisticsController.java

@@ -165,6 +165,33 @@ public class StoreOperationalStatisticsController {
         }
     }
 
+    @ApiOperation("根据ID查询历史统计记录详情")
+    @ApiOperationSupport(order = 3)
+    @ApiImplicitParams({
+            @ApiImplicitParam(
+                    name = "id",
+                    value = "历史记录ID",
+                    dataType = "Integer",
+                    paramType = "query",
+                    required = true
+            )
+    })
+    @GetMapping("/history/detail")
+    public R<StoreOperationalStatisticsHistory> getHistoryById(@RequestParam("id") Integer id) {
+        log.info("StoreOperationalStatisticsController.getHistoryById - id={}", id);
+        try {
+            if (id == null || id <= 0) {
+                return R.fail("ID不能为空且必须大于0");
+            }
+            
+            StoreOperationalStatisticsHistory history = storeOperationalStatisticsService.getHistoryById(id);
+            return R.data(history);
+        } catch (Exception e) {
+            log.error("查询历史统计记录详情失败 - id={}, error={}", id, e.getMessage(), e);
+            return R.fail("查询失败: " + e.getMessage());
+        }
+    }
+
     @ApiOperation("删除历史统计记录")
     @ApiOperationSupport(order = 4)
     @ApiImplicitParams({

+ 8 - 0
alien-store/src/main/java/shop/alien/store/service/StoreOperationalStatisticsService.java

@@ -50,6 +50,14 @@ public interface StoreOperationalStatisticsService {
     IPage<StoreOperationalStatisticsHistory> getHistoryList(Integer storeId, Integer page, Integer size);
 
     /**
+     * 根据ID查询历史统计记录详情
+     *
+     * @param id 历史记录ID
+     * @return 历史统计记录详情
+     */
+    StoreOperationalStatisticsHistory getHistoryById(Integer id);
+
+    /**
      * 删除历史统计记录(逻辑删除)
      *
      * @param id 历史记录ID

+ 134 - 1
alien-store/src/main/java/shop/alien/store/service/impl/StoreOperationalStatisticsServiceImpl.java

@@ -7,13 +7,19 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.http.*;
 import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
 import shop.alien.entity.store.*;
 import shop.alien.entity.store.vo.StoreOperationalStatisticsComparisonVo;
 import shop.alien.entity.store.vo.StoreOperationalStatisticsVo;
 import shop.alien.mapper.*;
 import shop.alien.store.service.StoreOperationalStatisticsService;
 import shop.alien.store.util.StatisticsComparisonImageUtil;
+import shop.alien.store.util.ai.AiAuthTokenUtil;
 import shop.alien.util.ali.AliOSSUtil;
 import shop.alien.util.common.RandomCreateUtil;
 import shop.alien.util.pdf.ImageToPdfUtil;
@@ -34,6 +40,7 @@ import java.util.*;
 @Slf4j
 @Service
 @RequiredArgsConstructor
+@RefreshScope
 public class StoreOperationalStatisticsServiceImpl implements StoreOperationalStatisticsService {
 
     private final LifeBrowseRecordMapper lifeBrowseRecordMapper;
@@ -56,6 +63,11 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
     private final StoreOperationalStatisticsHistoryMapper statisticsHistoryMapper;
     private final StoreTrackStatisticsMapper storeTrackStatisticsMapper;
     private final AliOSSUtil aliOSSUtil;
+    private final AiAuthTokenUtil aiAuthTokenUtil;
+    private final RestTemplate restTemplate;
+
+    @Value("${third-party-ai-store-summary-suggestion.base-url:}")
+    private String aiStatisticsAnalysisUrl;
 
     private static final String DATE_FORMAT = "yyyy-MM-dd";
     private static final String STAT_TYPE_DAILY = "DAILY";
@@ -221,9 +233,19 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
         comparison.setPriceListRanking(buildPriceListRankingComparison(currentStatistics.getPriceListRanking(), previousStatistics.getPriceListRanking()));
 
         // 保存历史记录(不包含PDF URL,PDF URL只在 generateStatisticsComparisonPdf 接口中保存)
-        saveStatisticsHistory(storeId, currentStartTime, currentEndTime, 
+        Integer historyId = saveStatisticsHistory(storeId, currentStartTime, currentEndTime, 
                 previousStartTime, previousEndTime, comparison, null);
 
+        // 异步调用AI接口进行数据分析
+        if (historyId != null) {
+            try {
+                callAiAnalysisAsync(historyId, storeId, comparison);
+            } catch (Exception e) {
+                log.error("调用AI分析接口失败 - historyId={}, error={}", historyId, e.getMessage(), e);
+                // AI分析失败不影响主流程,只记录日志
+            }
+        }
+
         return comparison;
     }
 
@@ -1035,6 +1057,31 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
     }
 
     @Override
+    public StoreOperationalStatisticsHistory getHistoryById(Integer id) {
+        log.info("StoreOperationalStatisticsServiceImpl.getHistoryById - id={}", id);
+        
+        // 参数校验
+        if (id == null || id <= 0) {
+            throw new IllegalArgumentException("历史记录ID不能为空且必须大于0");
+        }
+        
+        // 查询历史记录
+        LambdaQueryWrapper<StoreOperationalStatisticsHistory> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StoreOperationalStatisticsHistory::getId, id)
+               .eq(StoreOperationalStatisticsHistory::getDeleteFlag, 0);
+        
+        StoreOperationalStatisticsHistory history = statisticsHistoryMapper.selectOne(wrapper);
+        
+        if (history == null) {
+            log.warn("查询历史统计记录详情失败,记录不存在或已删除 - id={}", id);
+            throw new RuntimeException("历史记录不存在或已删除");
+        }
+        
+        log.info("查询历史统计记录详情成功 - id={}", id);
+        return history;
+    }
+
+    @Override
     public boolean deleteHistory(Integer id) {
         log.info("StoreOperationalStatisticsServiceImpl.deleteHistory - id={}", id);
         
@@ -1738,4 +1785,90 @@ public class StoreOperationalStatisticsServiceImpl implements StoreOperationalSt
         return comparison;
     }
 
+    /**
+     * 异步调用AI接口进行数据分析
+     * 
+     * @param historyId 历史记录ID
+     * @param storeId 店铺ID
+     * @param comparison 统计数据对比
+     */
+    private void callAiAnalysisAsync(Integer historyId, Integer storeId, StoreOperationalStatisticsComparisonVo comparison) {
+        // 如果AI接口URL未配置,跳过调用
+        if (!StringUtils.hasText(aiStatisticsAnalysisUrl)) {
+            log.warn("AI统计分析接口URL未配置,跳过AI分析 - historyId={}", historyId);
+            return;
+        }
+
+        try {
+            // 获取访问令牌
+            String accessToken = aiAuthTokenUtil.getAccessToken();
+            if (!StringUtils.hasText(accessToken)) {
+                log.error("调用AI分析接口失败,获取accessToken失败 - historyId={}", historyId);
+                return;
+            }
+
+            // 构建请求体,只发送id
+            Map<String, Object> requestBody = new HashMap<>();
+            requestBody.put("id", historyId);
+
+            // 构建请求头
+            HttpHeaders headers = new HttpHeaders();
+            headers.setContentType(MediaType.APPLICATION_JSON);
+            headers.set("Authorization", "Bearer " + accessToken);
+
+            log.info(requestBody.toString());
+
+            HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);
+
+            log.info("开始调用AI统计分析接口 - historyId={}, storeId={}", historyId, storeId);
+            ResponseEntity<String> response = restTemplate.postForEntity(
+                    aiStatisticsAnalysisUrl != null ? aiStatisticsAnalysisUrl : "", request, String.class);
+
+            if (response != null && response.getStatusCode() == HttpStatus.OK) {
+                String responseBody = response.getBody();
+                log.info("AI统计分析接口调用成功 - historyId={}, response={}", historyId, responseBody);
+                
+                // 解析AI返回的结果
+                if (StringUtils.hasText(responseBody)) {
+                    try {
+                        @SuppressWarnings("unchecked")
+                        Map<String, Object> responseMap = (Map<String, Object>) JSON.parseObject(responseBody, Map.class);
+                        if (responseMap != null) {
+                            String summary = extractStringValue(responseMap, "summary");
+                            String optimizationSuggestions = extractStringValue(responseMap, "optimizationSuggestions");
+                            
+                            // 更新历史记录的AI分析结果
+                            if (StringUtils.hasText(summary) || StringUtils.hasText(optimizationSuggestions)) {
+                                updateHistoryAiAnalysis(historyId, 1, summary, optimizationSuggestions);
+                                log.info("更新AI分析结果成功 - historyId={}", historyId);
+                            }
+                        }
+                    } catch (Exception e) {
+                        log.warn("解析AI分析结果失败 - historyId={}, responseBody={}, error={}", 
+                                historyId, responseBody, e.getMessage());
+                    }
+                }
+            } else {
+                log.warn("AI统计分析接口调用失败 - historyId={}, statusCode={}", 
+                        historyId, response != null ? response.getStatusCode() : null);
+            }
+        } catch (Exception e) {
+            log.error("调用AI统计分析接口异常 - historyId={}, error={}", historyId, e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 从Map中提取String值
+     */
+    private String extractStringValue(Map<String, Object> map, String key) {
+        if (map == null) {
+            return null;
+        }
+        Object value = map.get(key);
+        if (value == null) {
+            return null;
+        }
+        return value.toString();
+    }
+
 }