Merge branch 'cc_20251027_latest_order' into 'master'

门店最近订货时间定时任务

See merge request hangzhou/java/custom_zxjp!175
This commit is contained in:
苏竹红
2025-10-27 08:59:01 +00:00
11 changed files with 290 additions and 4 deletions

View File

@@ -230,4 +230,6 @@ public class CommonConstants {
* refreshToken有效期单位秒
*/
public static final int REFRESH_TOKEN_EXPIRE = 30 * 24 * 60 * 60;
public static final int BATCH_SIZE = 200;
}

View File

@@ -1,5 +1,6 @@
package com.cool.store.dao;
import com.cool.store.dto.store.StoreOrderTimeDTO;
import com.cool.store.entity.StoreDO;
import com.cool.store.mapper.StoreMapper;
import com.cool.store.response.MiniShopsResponse;
@@ -83,4 +84,22 @@ public class StoreDao {
return storeMapper.getStoreNumByStoreCodes(storeCodeIds);
}
/**
* 新增或编辑最新订货时间
* @param dtoList 门店最新订货时间DTO列表
* @return int
*/
public void batchInsertOrUpdateOrderTime(List<StoreOrderTimeDTO> dtoList) {
if (CollectionUtils.isEmpty(dtoList)) {
return ;
}
storeMapper.batchInsertOrUpdateOrderTime(dtoList);
}
/**
* 查询所有门店id和门店编码
*/
public List<StoreDO> getAllStoreIdAndNum(List<String> storeStatus) {
return storeMapper.getAllStoreIdAndNum(storeStatus);
}
}

View File

@@ -1,6 +1,7 @@
package com.cool.store.mapper;
import com.cool.store.dto.store.StoreAreaDTO;
import com.cool.store.dto.store.StoreOrderTimeDTO;
import com.cool.store.entity.StoreDO;
import com.cool.store.response.MiniShopsResponse;
import org.apache.ibatis.annotations.Mapper;
@@ -47,4 +48,15 @@ public interface StoreMapper {
List<StoreAreaDTO> listStoreByRegionPathList(@Param("regionPathList") List<String> regionPathList);
/**
* 批量新增或编辑最新订货时间
* @param dtoList 门店最新订货时间DTO列表
* @return int
*/
int batchInsertOrUpdateOrderTime(@Param("dtoList") List<StoreOrderTimeDTO> dtoList);
/**
* 查询所有门店id和门店编码
*/
List<StoreDO> getAllStoreIdAndNum(@Param("storeStatus") List<String> storeStatus);
}

View File

@@ -222,4 +222,37 @@
</foreach>
</if>
</select>
<insert id="batchInsertOrUpdateOrderTime">
INSERT INTO store_extend_info_${enterpriseId}
<trim prefix="(" suffix=")" suffixOverrides=",">
store_id,
latest_order_time
</trim>
VALUES
<foreach collection="dtoList" item="dto" separator=",">
<trim prefix="(" suffix=")" suffixOverrides=",">
#{dto.storeId},
#{dto.latestOrderTime}
</trim>
</foreach>
ON DUPLICATE KEY UPDATE
<trim suffixOverrides=",">
store_id = VALUES(store_id),
latest_order_time = VALUES(latest_order_time),
update_time = now(),
</trim>
</insert>
<select id="getAllStoreIdAndNum" resultType="com.cool.store.entity.StoreDO">
SELECT store_id, store_num
FROM store_${enterpriseId}
WHERE is_delete = 'effective'
<if test="storeStatus != null and !storeStatus.isEmpty()">
AND store_status IN
<foreach item="item" collection="storeStatus" separator="," open="(" close=")">
#{item}
</foreach>
</if>
</select>
</mapper>

View File

@@ -0,0 +1,27 @@
package com.cool.store.dto.store;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* <p>
* 门店最新订货时间DTO
* </p>
*
* @author wangff
* @since 2025/10/23
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StoreOrderTimeDTO {
@ApiModelProperty("门店id")
private String storeId;
@ApiModelProperty("最新订货时间")
private Date latestOrderTime;
}

View File

@@ -0,0 +1,33 @@
package com.cool.store.request.bigdata;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* <p>
* 最新订货日期Request
* </p>
*
* @author wangff
* @since 2025/10/23
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LatestOrderDateRequest {
/**
* 页码
*/
private Integer pageNum;
/**
* 页数量
*/
private Integer pageSize;
/**
* 门店编码列表
*/
private String store_code;
}

View File

@@ -0,0 +1,21 @@
package com.cool.store.response.bigdata;
import lombok.Data;
import java.util.List;
/**
* <p>
* 分页对象
* </p>
*
* @author wangff
* @since 2025/10/27
*/
@Data
public class ApiPageResponse<T> {
private Integer total;
private List<T> list;
private Integer pageNum;
private Integer pageSize;
}

View File

@@ -0,0 +1,24 @@
package com.cool.store.response.bigdata;
import lombok.Data;
/**
* <p>
* 最新订货日期Response
* </p>
*
* @author wangff
* @since 2025/10/23
*/
@Data
public class LatestOrderDateResponse {
/**
* 门店编码
*/
private String store_code;
/**
* 最新订货日期yyyy-MM-dd
*/
private String latest_buy_date;
}

View File

@@ -1,8 +1,10 @@
package com.cool.store.service;
import com.cool.store.request.bigdata.LatestOrderDateRequest;
import com.cool.store.request.bigdata.ProfitDataRequest;
import com.cool.store.request.oppty.CityRequest;
import com.cool.store.response.bigdata.ActDataResponse;
import com.cool.store.response.bigdata.LatestOrderDateResponse;
import com.cool.store.response.bigdata.ProfitDataResponse;
import com.cool.store.response.bigdata.ProfitRateResponse;
import com.cool.store.response.oppty.CityResponse;
@@ -53,5 +55,11 @@ public interface ThirdBigDataService {
*/
ActDataResponse getActData(ProfitDataRequest requestBody);
/**
* 获取门店最新订货日期
* @param requestBody 最新订货日期Request
* @return 最新订货日期Response列表
*/
List<LatestOrderDateResponse> getLatestOrderDate(LatestOrderDateRequest requestBody);
}

View File

@@ -3,12 +3,10 @@ package com.cool.store.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.request.bigdata.LatestOrderDateRequest;
import com.cool.store.request.bigdata.ProfitDataRequest;
import com.cool.store.request.oppty.CityRequest;
import com.cool.store.response.bigdata.ActDataResponse;
import com.cool.store.response.bigdata.ApiResponse;
import com.cool.store.response.bigdata.ProfitDataResponse;
import com.cool.store.response.bigdata.ProfitRateResponse;
import com.cool.store.response.bigdata.*;
import com.cool.store.response.oppty.CityResponse;
import com.cool.store.response.oppty.OpportunityApiResponse;
import com.cool.store.response.oppty.OpportunityDetailResponse;
@@ -96,6 +94,15 @@ public class ThirdBigDataServiceImpl implements ThirdBigDataService {
return executeApiCall(url, requestBody, ActDataResponse.class);
}
@Override
public List<LatestOrderDateResponse> getLatestOrderDate(LatestOrderDateRequest requestBody) {
String url = apiUrl + "api/web/v1/buy/latest_buy_date";
JavaType javaType = objectMapper.getTypeFactory()
.constructParametricType(ApiPageResponse.class, LatestOrderDateResponse.class);
ApiPageResponse<LatestOrderDateResponse> response = executeApiCallWithGenericType(url, requestBody, javaType);
return response.getList();
}
private <T> T executeApiCall(String url, Object requestBody, Class<T> responseType) {
// 1. 打印请求前日志
@@ -136,6 +143,44 @@ public class ThirdBigDataServiceImpl implements ThirdBigDataService {
}
}
private <T> T executeApiCallWithGenericType(String url, Object requestBody, JavaType responseType) {
// 1. 打印请求前日志
logRequest(url, requestBody);
try {
Request request = buildRequest(requestBody, url);
try (Response response = okHttpClient.newCall(request).execute()) {
// 2. 获取原始响应内容
String responseBody = response.body().string();
// 3. 打印响应日志
logResponse(url, response.code(), responseBody);
if (!response.isSuccessful()) {
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,
"HTTP请求失败状态码: " + response.code());
}
// 4. 解析响应
JavaType javaType = objectMapper.getTypeFactory()
.constructParametricType(OpportunityApiResponse.class, responseType);
OpportunityApiResponse<T> apiResponse = objectMapper.readValue(responseBody, javaType);
if (apiResponse.getCode() != 0) {
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, apiResponse.getMsg());
}
return apiResponse.getData();
}
} catch (ServiceException e) {
throw e;
} catch (Exception e) {
log.error("API调用异常 - URL: {}, 错误: {}", url, e.getMessage(), e);
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "接口调用异常: " + e.getMessage());
}
}
private Request buildRequest(Object requestBody, String url) {
Map<String, Object> params = JsonUtils.parseJsonToMap(JSONObject.toJSONString(requestBody));

View File

@@ -1,5 +1,6 @@
package com.cool.store.job;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.constants.CommonConstants;
@@ -7,6 +8,7 @@ import com.cool.store.dao.*;
import com.cool.store.dto.*;
import com.cool.store.dto.decoration.ConstructionScheduleDTO;
import com.cool.store.dto.openPreparation.OpenPlanShopInfoDTO;
import com.cool.store.dto.store.StoreOrderTimeDTO;
import com.cool.store.entity.*;
import com.cool.store.enums.*;
import com.cool.store.enums.point.ShopStatusEnum;
@@ -19,11 +21,14 @@ import com.cool.store.mapper.TrainingExperienceMapper;
import com.cool.store.mq.producer.SimpleMessageService;
import com.cool.store.mq.util.HttpRestTemplateService;
import com.cool.store.request.ZxjpApiRequest;
import com.cool.store.request.bigdata.LatestOrderDateRequest;
import com.cool.store.request.xfsgFirstOrderListRequest;
import com.cool.store.response.bigdata.LatestOrderDateResponse;
import com.cool.store.response.xfsgFirstOderListResponse;
import com.cool.store.service.*;
import com.cool.store.service.impl.CommonService;
import com.cool.store.utils.CoolDateUtils;
import com.cool.store.utils.MDCUtils;
import com.cool.store.utils.NumberConverter;
import com.cool.store.utils.poi.DateUtils;
import com.cool.store.utils.poi.StringUtils;
@@ -40,6 +45,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
@@ -111,6 +117,10 @@ public class XxlJobHandler {
@Resource
PushService pushService;
@Resource
StoreDao storeDao;
@Resource
ThirdBigDataService thirdBigDataService;
/**
@@ -395,4 +405,56 @@ public class XxlJobHandler {
}
}
@XxlJob("latestOrderDate")
public void latestOrderDate() {
log.info("------start latestOrderDate------");
MDCUtils.put(CommonConstants.REQUEST_ID, UUID.randomUUID().toString());
String param = XxlJobHelper.getJobParam();
List<String> storeStatus = null;
if (StringUtils.isNotBlank(param)) {
storeStatus = Arrays.asList(param.split(","));
}
boolean hasNext = true;
int pageNum = 1;
int pageSize = CommonConstants.BATCH_SIZE;
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
while (hasNext) {
PageHelper.startPage(pageNum, pageSize);
List<StoreDO> storeList = storeDao.getAllStoreIdAndNum(storeStatus);
if (CollectionUtils.isEmpty(storeList)) {
break;
}
hasNext = storeList.size() >= pageSize;
List<String> storeNums = CollStreamUtil.toList(storeList, StoreDO::getStoreNum);
Map<String, String> storeIdMap = CollStreamUtil.toMap(storeList, StoreDO::getStoreNum, StoreDO::getStoreId);
LatestOrderDateRequest request = new LatestOrderDateRequest(1, pageSize, String.join(",", storeNums));
List<LatestOrderDateResponse> resList = thirdBigDataService.getLatestOrderDate(request);
log.info("接口请求门店数量:{},返回门店数:{}", storeList.size(), resList.size());
if (CollectionUtils.isNotEmpty(resList)) {
try {
List<StoreOrderTimeDTO> updateList = resList.stream()
.map(v -> {
Date date = parseDate(v, dateFormat);
return Objects.nonNull(date) ? new StoreOrderTimeDTO(storeIdMap.get(v.getStore_code()), date) : null;
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
storeDao.batchInsertOrUpdateOrderTime(updateList);
} catch (Exception e) {
log.error("获取最新订货时间失败", e);
}
}
pageNum++;
}
log.info("------end latestOrderDate------");
}
public Date parseDate(LatestOrderDateResponse v, DateFormat format) {
try {
return format.parse(v.getLatest_buy_date());
} catch (ParseException e) {
log.error("日期转化失败,storeCode:{},latestBuyDate:{}", v.getStore_code(), v.getLatest_buy_date());
}
return null;
}
}