提交 0c5c3897 authored 作者: 窦馨雨's avatar 窦馨雨

合并分支 'dxy' 到 'qa'

CP计划小程序改造,新增照片逻辑保存 查看合并请求 !65
......@@ -28,8 +28,8 @@ public class TencentLocationController {
return R.success(addressByLngLat);
}
@GetMapping("/list")
public R getProvinceDistinctList(){
return R.success(tencentLocationQueryService.getAddressList());
}
// @GetMapping("/list")
// public R getProvinceDistinctList(){
// return R.success(tencentLocationQueryService.getAddressList());
// }
}
......@@ -3,7 +3,9 @@ package com.wangxiaolu.promotion.controller.user.tem;
import com.wangxiaolu.promotion.common.redis.service.RedisCache;
import com.wangxiaolu.promotion.common.util.DataUtils;
import com.wangxiaolu.promotion.common.util.EnvUtil;
import com.wangxiaolu.promotion.domain.user.mapper.entity.WxTemporaryInfoDelayDO;
import com.wangxiaolu.promotion.exception.ParamException;
import com.wangxiaolu.promotion.pojo.activity.temporary.dto.WxTemporaryInfoDelayDtO;
import com.wangxiaolu.promotion.pojo.user.dto.WxTemporaryInfoDto;
import com.wangxiaolu.promotion.pojo.user.vo.WxTemporaryEnrollVo;
import com.wangxiaolu.promotion.result.basedata.R;
......@@ -15,6 +17,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* @author : liqiulin
* @date : 2024-04-03 17
......@@ -67,12 +72,20 @@ public class TemporaryInfoCoreController {
@PutMapping("/temporary/changeStoreInfo")
public R changeUserInfo(@RequestBody WxTemporaryEnrollVo wxTemporaryEnrollVo) {
if (wxTemporaryEnrollVo.getOpenId() == null){
throw new ParamException(RCode.WX_OPENID_PARAM_ERROR, null);
}
WxTemporaryInfoDto temporaryDto = new WxTemporaryInfoDto();
BeanUtils.copyProperties(wxTemporaryEnrollVo, temporaryDto);
return R.success(weChatUserCoreService.saveWxUserStoreInfoTemporary(temporaryDto));
if (wxTemporaryEnrollVo.getOpenId() == null) {
throw new ParamException(RCode.WX_OPENID_PARAM_ERROR, null);
}
// 转换为延迟表实体
WxTemporaryInfoDelayDtO delayEntity = new WxTemporaryInfoDelayDtO();
BeanUtils.copyProperties(wxTemporaryEnrollVo, delayEntity);
// 设置数据日期(当天)、创建时间、未处理状态
delayEntity.setCreateTime(LocalDateTime.now());
delayEntity.setCreateTime(LocalDateTime.now());
delayEntity.setIsProcessed(0);
// 保存到延迟表
boolean saveResult = weChatUserCoreService.saveDelayData(delayEntity);
return R.success(saveResult);
}
}
......@@ -51,7 +51,7 @@ public class TemporaryInfoQueryController {
if (!DataUtils.phonePattern(wxTemporaryLoginVo.getPhone())) {
throw new ParamException(RCode.PHONE_PARAM_ERROR, null);
}
LoginVo loginVo = weChatUserQueryService.temporaryLoginByPhone(wxTemporaryLoginVo.getPhone());
LoginVo loginVo = weChatUserQueryService.loginTemporaryByOpenIdAndPhone(wxTemporaryLoginVo.getOpenId(),wxTemporaryLoginVo.getPhone());
return R.success(loginVo);
}
......@@ -85,7 +85,7 @@ public class TemporaryInfoQueryController {
if (StringUtils.isBlank(temporaryRegisterVo.getOpenId())) {
throw new ParamException(RCode.LOGIN_PARAM_ERROR, null);
}
return R.success(weChatUserQueryService.findTemporaryWorkStore(temporaryRegisterVo.getOpenId()));
return R.success(weChatUserQueryService.findTemporaryWorkStore(temporaryRegisterVo.getOpenId(),temporaryRegisterVo.getDate()));
}
private void phontAndOpenIdVerify(WxTemporaryLoginVo wxTemporaryLoginVo) {
......
......@@ -52,10 +52,11 @@ public interface ActivityPlanInfoMapper extends BaseMapper<ActivityPlanInfoDo> {
"<script>",
"SELECT DISTINCT api.store_code AS storeCode, api.store_name AS storeName ",
"FROM activity_plan_info api ",
"WHERE api.`date` > #{date} ",
"WHERE api.`date` >= #{date} ",
"<if test='storeNameKeyword != null and storeNameKeyword != \"\"'>",
"AND api.store_name LIKE CONCAT('%', #{storeNameKeyword}, '%')",
"</if>",
"AND is_delete = 1 ",
"</script>"
})
List<Map<String, String>> selectStoreInfoByCondition(
......
......@@ -4,6 +4,9 @@ import com.wangxiaolu.promotion.domain.user.wrapperQo.TemporaryWrapper;
import com.wangxiaolu.promotion.pojo.PageInfo;
import com.wangxiaolu.promotion.pojo.user.dto.WxTemporaryInfoDto;
import java.util.List;
import java.util.Map;
/**
* @author : liqiulin
* @date : 2024-04-08 16
......@@ -30,4 +33,9 @@ public interface TemporaryInfoDao {
WxTemporaryInfoDto selectByPhone(String phone);
int saveWxUserStoreInfoTemporary(WxTemporaryInfoDto temporaryDto);
Map<String,Object> selectStoreAndPlan(String openId, String date);
int batchInsertOrUpdate(List<WxTemporaryInfoDto> list);
}
package com.wangxiaolu.promotion.domain.user.dao;
import com.wangxiaolu.promotion.domain.user.mapper.entity.WxTemporaryInfoDelayDO;
import com.wangxiaolu.promotion.pojo.activity.temporary.dto.WxTemporaryInfoDelayDtO;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
@Repository
public interface WxTemporaryInfoDelayDao {
// 查询指定时间范围未处理的数据
List<WxTemporaryInfoDelayDtO> selectUnprocessedData(LocalDateTime startTime, LocalDateTime endTime);
// 插入单条延迟数据
int insert(WxTemporaryInfoDelayDtO delayEntity);
// 批量更新处理状态
int batchUpdateProcessedStatus(List<Long> idList, Integer isProcessed);
}
\ No newline at end of file
......@@ -21,6 +21,7 @@ import org.springframework.util.CollectionUtils;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
......@@ -102,6 +103,45 @@ public class TemporaryInfoDaoImpl implements TemporaryInfoDao {
return temporaryInfoMapper.updateById(entity);
}
@Override
public Map<String,Object> selectStoreAndPlan(String openId, String date) {
return temporaryInfoMapper.selectStoreAndPlan(openId,date);
}
@Override
public int batchInsertOrUpdate(List<WxTemporaryInfoDto> list) {
// 空列表防护:避免无效SQL执行
int affectRows;
if (CollectionUtils.isEmpty(list)) {
return 0;
}
try {
// 1. 批量转换DTO → DO
List<TemporaryInfoDO> doList = new ArrayList<>(list.size());
for (WxTemporaryInfoDto dto : list) {
TemporaryInfoDO entity = new TemporaryInfoDO();
BeanUtils.copyProperties(dto, entity);
doList.add(entity);
}
// 2. 调用Mapper层的批量插入/更新方法
affectRows = temporaryInfoMapper.batchInsertOrUpdate(doList);
// 3. 异常捕获:处理唯一键冲突(复用项目已有异常逻辑)
} catch (Exception e) {
affectRows = 0;
String eMsg = e.getCause() != null ? e.getCause().getMessage() : e.getMessage();
if (eMsg.contains("for key 'open_id_unique'")) {
throw new ParamException(RCode.USER_WXOPENID_UNIQUE_ERROR);
} else if (eMsg.contains("for key 'phone_unique'")) {
throw new ParamException(RCode.USER_PHONE_UNIQUE_ERROR);
}
}
return affectRows;
}
private LambdaQueryWrapper<TemporaryInfoDO> buildQueryList(TemporaryWrapper tw) {
LambdaQueryWrapper<TemporaryInfoDO> queryWrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotBlank(tw.getOpenId())) {
......
package com.wangxiaolu.promotion.domain.user.dao.impl;
import com.wangxiaolu.promotion.common.util.BeanUtils;
import com.wangxiaolu.promotion.domain.user.dao.WxTemporaryInfoDelayDao;
import com.wangxiaolu.promotion.domain.user.mapper.WxTemporaryInfoDelayMapper;
import com.wangxiaolu.promotion.domain.user.mapper.entity.WxTemporaryInfoDelayDO;
import com.wangxiaolu.promotion.pojo.activity.temporary.dto.WxTemporaryInfoDelayDtO;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class WxTemporaryInfoDelayDaoImpl implements WxTemporaryInfoDelayDao {
@Resource
private WxTemporaryInfoDelayMapper delayMapper;
@Override
public List<WxTemporaryInfoDelayDtO> selectUnprocessedData(LocalDateTime startTime, LocalDateTime endTime) {
// 1. 查询数据库获取DO列表
List<WxTemporaryInfoDelayDO> wxTemporaryInfoDelayDOS = delayMapper.selectByTimeAndStatus(startTime, endTime, 0);
// 2. 调用类内的通用转换方法完成DO转DTO
return copyListProperties(wxTemporaryInfoDelayDOS, WxTemporaryInfoDelayDtO.class);
}
@Override
public int insert(WxTemporaryInfoDelayDtO delayEntity) {
WxTemporaryInfoDelayDO delayDO = new WxTemporaryInfoDelayDO();
BeanUtils.copyProperties(delayEntity, delayDO);
return delayMapper.insert(delayDO);
}
@Override
public int batchUpdateProcessedStatus(List<Long> idList, Integer isProcessed) {
if (idList == null || idList.isEmpty()) {
return 0;
}
return delayMapper.batchUpdateStatus(idList, isProcessed);
}
private <S, T> List<T> copyListProperties(List<S> sourceList, Class<T> targetClass) {
// 空值判断,避免空指针
if (sourceList == null || sourceList.isEmpty()) {
return new ArrayList<>();
}
// 批量转换源列表为目标列表
return sourceList.stream()
.map(source -> {
try {
// 反射创建目标对象实例
T target = targetClass.getDeclaredConstructor().newInstance();
// 拷贝属性
BeanUtils.copyProperties(source, target);
return target;
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException |
InvocationTargetException e) {
// 转换失败抛出运行时异常,便于排查问题
throw new RuntimeException("对象列表转换失败,目标类:" + targetClass.getName(), e);
}
})
.collect(Collectors.toList());
}
}
\ No newline at end of file
......@@ -4,8 +4,12 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wangxiaolu.promotion.domain.user.mapper.entity.TemporaryInfoDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
/**
* @author a02200059
* @description 针对表【temporary_info】的数据库操作Mapper
......@@ -19,6 +23,22 @@ public interface TemporaryInfoMapper extends BaseMapper<TemporaryInfoDO> {
// 根据openId查询非保密数据,保密数据不返回:身份证号、身份证照片等信息
TemporaryInfoDO getUnimportantData(@Param("openId") String openId);
@Select({
"SELECT ti.store_code AS storeCode, ",
" ti.store_name AS storeName, ",
" api.id AS planId ",
"FROM temporary_info ti ",
"LEFT JOIN activity_plan_info api ON ti.store_name = api.store_name ",
" AND api.is_delete = 1 ",
" AND api.`date` = #{date} ",
"WHERE ti.open_id = #{openId}"
})
Map<String, Object> selectStoreAndPlan(
@Param("openId") String openId,
@Param("date") String date
);
int batchInsertOrUpdate(List<TemporaryInfoDO> doList);
}
......
package com.wangxiaolu.promotion.domain.user.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wangxiaolu.promotion.domain.user.mapper.entity.WxTemporaryInfoDelayDO;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDateTime;
import java.util.List;
/**
* 延迟临时表Mapper
*/
public interface WxTemporaryInfoDelayMapper extends BaseMapper<WxTemporaryInfoDelayDO> {
/**
* 查询指定时间范围内未处理的数据
*/
List<WxTemporaryInfoDelayDO> selectByTimeAndStatus(
@Param("startTime") LocalDateTime startTime,
@Param("endTime") LocalDateTime endTime,
@Param("isProcessed") Integer isProcessed
);
/**
* 批量更新处理状态
*/
int batchUpdateStatus(
@Param("idList") List<Long> idList,
@Param("isProcessed") Integer isProcessed
);
}
\ No newline at end of file
package com.wangxiaolu.promotion.domain.user.mapper.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 微信门店数据延迟保存临时表实体
*/
@Data
@TableName("wx_temporary_info_delay")
public class WxTemporaryInfoDelayDO {
/**
* 主键ID
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 微信OpenId
*/
private String openId;
/**
* 门店名称
*/
private String storeName;
/**
* 门店地址
*/
private String storeAddress;
/**
* 联系电话
*/
private String contactPhone;
/**
* 数据暂存时间
*/
private LocalDateTime createTime;
/**
* 是否已处理:0-未处理 1-已处理
*/
private Integer isProcessed;
/**
* 更新时间
*/
private LocalDateTime updateTime;
}
\ No newline at end of file
......@@ -45,14 +45,19 @@ public enum ActivityPhotoType {
POS_SELL_VOUCHER(8),
/**
* POS照片
* 试吃照片
*/
POS_PHOTO(9),
TASTY_PHOTO(9),
/**
* 随机任务照片
* 配发赠品照片
*/
SEND_GIFT_PHOTO(10),
/**
* 高峰期在岗
* 更改固定任务:下午18点15任务
*/
RANDOM_TASK(10)
RANDOM_TASK(11),
TASTY_MATERIALS(12)
;
private int type;
......
......@@ -156,6 +156,24 @@ public class TemporaryActivityReportedDto {
private List<TemporaryActivityPhotoDto> randTaskClockPhotoUrls;
private List<TemporaryActivityPhotoDto> posTaskClockPhotoUrls;
/**
* 试吃品照片
*/
private List<String> scpPhotoUrls;
/**
* 配发赠品照片
*/
private List<String> pfzpPhotoUrls;
/**
* 高峰期在岗
*/
private List<String> gfqPhotoUrls;
/**
* 试吃必备物料照片
*/
private List<String> scbbwlPhotoUrls;
/**
* 创建时间
......
package com.wangxiaolu.promotion.pojo.activity.temporary.dto;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 微信门店数据延迟保存临时表实体
*/
@Data
public class WxTemporaryInfoDelayDtO {
/**
* 主键ID
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 微信OpenId
*/
private String openId;
/**
* 门店名称
*/
private String storeName;
/**
* 门店地址
*/
private String storeAddress;
/**
* 联系电话
*/
private String contactPhone;
/**
* 数据暂存时间
*/
private LocalDateTime createTime;
/**
* 是否已处理:0-未处理 1-已处理
*/
private Integer isProcessed;
/**
* 更新时间
*/
private LocalDateTime updateTime;
}
\ No newline at end of file
......@@ -67,6 +67,24 @@ public class TemporaryActivityDataVo {
*/
private List<String> psvPhotoUrls;
private List<String> psvChangePhotoUrls;
/**
* 试吃品照片
*/
private List<String> scpPhotoUrls;
/**
* 配发赠品照片
*/
private List<String> pfzpPhotoUrls;
/**
* 高峰期在岗
*/
private List<String> gfqPhotoUrls;
/**
* 试吃必备物料照片
*/
private List<String> scbbwlPhotoUrls;
// 促销员联系电话
private String temporaryPhone;
// 执行方式
......
......@@ -16,5 +16,6 @@ public class TemporaryRegisterVo {
private String openId;
private String phone;
private Long id;
private String date;
}
......@@ -109,11 +109,8 @@ public class TemporaryActivityCoreServiceImpl implements TemporaryActivityCoreSe
// 图片增量保存
saveActivityPhotoV2(temActDto);
// 如果数量小于2 修改状态为 SUBMITTED 已保存
if(ObjectUtil.isAllNotEmpty(temActDto.getTgscPhotoUrls(),temActDto.getTghdPhotoUrls(),temActDto.getTgcjPhotoUrls())
&& temActDto.getTgscPhotoUrls().size()>=2 && temActDto.getTghdPhotoUrls().size()>=2 && temActDto.getTgcjPhotoUrls().size()>=2 ){
if(ObjectUtil.isAllNotEmpty(temActDto.getTgscPhotoUrls(),temActDto.getTghdPhotoUrls(),temActDto.getTgcjPhotoUrls())){
temActDto.setApproveStatus(TemActApproveStatus.APPROVED);
}else {
temActDto.setApproveStatus(TemActApproveStatus.SUBMITTED);
}
WxTemporaryInfoDto wxTemporaryInfoDto = temporaryInfoDao.selectOneById(temActDto.getTemporaryId());
temActDto.setTemporaryPhone(wxTemporaryInfoDto.getPhone());
......@@ -287,10 +284,38 @@ public class TemporaryActivityCoreServiceImpl implements TemporaryActivityCoreSe
tempActivityPhotoDao.saveReportedList(null, temporaryId, reportedId, ActivityPhotoType.TGCJ.getType(), temActDto.getTgcjPhotoUrls());
}
// POS机页面凭证
// if (!CollectionUtils.isEmpty(temActDto.getPsvPhotoUrls())) {
// tempActivityPhotoDao.saveReportedList(temporaryId, reportedId, ActivityPhotoType.POS_SELL_VOUCHER.getType(), temActDto.getPsvPhotoUrls());
// }
// 试吃品
if (CollectionUtils.isEmpty(temActDto.getScpPhotoUrls())) {
tempActivityPhotoDao.deleteList(reportedId, ActivityPhotoType.TASTY_PHOTO.getType());
}else {
tempActivityPhotoDao.saveReportedList(null,temporaryId, reportedId, ActivityPhotoType.TASTY_PHOTO.getType(), temActDto.getTgscPhotoUrls());
}
// 配发赠品照片
if (CollectionUtils.isEmpty(temActDto.getGfqPhotoUrls())) {
tempActivityPhotoDao.deleteList(reportedId, ActivityPhotoType.SEND_GIFT_PHOTO.getType());
} else {
tempActivityPhotoDao.saveReportedList(null,temporaryId, reportedId, ActivityPhotoType.SEND_GIFT_PHOTO.getType(), temActDto.getGfqPhotoUrls());
}
//POS机页面凭证
if (CollectionUtils.isEmpty(temActDto.getPsvPhotoUrls())) {
tempActivityPhotoDao.deleteList(reportedId, ActivityPhotoType.POS_SELL_VOUCHER.getType());
} else {
tempActivityPhotoDao.saveReportedList(null,temporaryId, reportedId, ActivityPhotoType.POS_SELL_VOUCHER.getType(), temActDto.getPsvPhotoUrls());
}
//高峰期在岗
if (CollectionUtils.isEmpty(temActDto.getGfqPhotoUrls())) {
tempActivityPhotoDao.deleteList(reportedId, ActivityPhotoType.RANDOM_TASK.getType());
} else {
tempActivityPhotoDao.saveReportedList(null,temporaryId, reportedId, ActivityPhotoType.RANDOM_TASK.getType(), temActDto.getGfqPhotoUrls());
}
// 试吃必备物料照片
if (CollectionUtils.isEmpty(temActDto.getScbbwlPhotoUrls())) {
tempActivityPhotoDao.deleteList(reportedId, ActivityPhotoType.TASTY_MATERIALS.getType());
} else {
tempActivityPhotoDao.saveReportedList(null,temporaryId, reportedId, ActivityPhotoType.TASTY_MATERIALS.getType(), temActDto.getScbbwlPhotoUrls());
}
}
// private void saveActivityPhoto(TemporaryActivityReportedDto temActDto) {
......
......@@ -90,7 +90,7 @@ public class TemporaryActivityQueryServiceImpl implements TemporaryActivityQuery
TemporaryPhotoWrapper posWrapper = new TemporaryPhotoWrapper();
posWrapper.setTemporaryId(dto.getTemporaryId())
.setClockId(clockInfo.getId())
.setType(ActivityPhotoType.POS_PHOTO.getType() );
.setType(ActivityPhotoType.POS_SELL_VOUCHER.getType() );
List<TemporaryActivityPhotoDto> posTaskClockPhotoUrls = temporaryActivityPhotoDao.selectPhotos(posWrapper);
dto.setPosTaskClockPhotoUrls(posTaskClockPhotoUrls);
......
......@@ -109,7 +109,7 @@ public class TemporaryActivityTaskClockServiceImpl extends ServiceImpl<Temporary
.setClockId(dto.getId())
.setReportId(dto.getReportedId())
.setCreateDate(DateUtil.today())
.setTaskType(ActivityPhotoType.POS_PHOTO.getType())
.setTaskType(ActivityPhotoType.POS_SELL_VOUCHER.getType())
.setIsDelete(FlagType.NO.getType());
TemporaryActivityTaskClockDO taskClockDO1 = temporaryActivityTaskClockDao.selectOne(wrapper);
if (ObjectUtil.isNotEmpty(taskClockDO1)) {
......@@ -124,7 +124,7 @@ public class TemporaryActivityTaskClockServiceImpl extends ServiceImpl<Temporary
.setReportedId(null)
.setPlanId(dto.getPlanId())
.setClockTime(null)
.setTaskType(ActivityPhotoType.POS_PHOTO.getType())
.setTaskType(ActivityPhotoType.POS_SELL_VOUCHER.getType())
.setTaskStatus(ActivityClockTaskStatus.STARTING.getType())
.setRequiredlockTime(null)
.setActivityPatternId(dto.getActivityPatternId())
......@@ -244,7 +244,7 @@ public class TemporaryActivityTaskClockServiceImpl extends ServiceImpl<Temporary
res.setEditableFlag(true);
}
}
if (taskClockDO.getTaskType() == ActivityPhotoType.POS_PHOTO.getType()){
if (taskClockDO.getTaskType() == ActivityPhotoType.POS_SELL_VOUCHER.getType()){
res.setEditableFlag(true);
}
}
......
package com.wangxiaolu.promotion.service.user;
import com.wangxiaolu.promotion.domain.user.mapper.entity.WxTemporaryInfoDelayDO;
import com.wangxiaolu.promotion.pojo.activity.temporary.dto.WxTemporaryInfoDelayDtO;
import java.time.LocalDateTime;
import java.util.List;
/**
* 延迟临时表Service(适配前端入参字段)
*/
public interface WxTemporaryInfoDelayService {
/**
* 保存延迟数据到临时表(含storeCode/dataDate)
*/
boolean saveDelayData(WxTemporaryInfoDelayDtO delayEntity);
/**
* 查询指定时间范围未处理的数据
*/
List<WxTemporaryInfoDelayDtO> listUnprocessedData(LocalDateTime startTime, LocalDateTime endTime);
/**
* 批量更新处理状态
*/
boolean batchUpdateProcessedStatus(List<Long> idList, Integer isProcessed);
}
\ No newline at end of file
package com.wangxiaolu.promotion.service.user.impl;
import com.wangxiaolu.promotion.domain.user.dao.WxTemporaryInfoDelayDao;
import com.wangxiaolu.promotion.domain.user.mapper.entity.WxTemporaryInfoDelayDO;
import com.wangxiaolu.promotion.pojo.activity.temporary.dto.WxTemporaryInfoDelayDtO;
import com.wangxiaolu.promotion.service.user.WxTemporaryInfoDelayService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class WxTemporaryInfoDelayServiceImpl implements WxTemporaryInfoDelayService {
@Resource
private WxTemporaryInfoDelayDao delayDao;
@Override
public boolean saveDelayData(WxTemporaryInfoDelayDtO delayEntity) {
// 调用DAO插入数据(含storeCode/dataDate)
return delayDao.insert(delayEntity) > 0;
}
@Override
public List<WxTemporaryInfoDelayDtO> listUnprocessedData(LocalDateTime startTime, LocalDateTime endTime) {
return delayDao.selectUnprocessedData(startTime, endTime);
}
@Override
public boolean batchUpdateProcessedStatus(List<Long> idList, Integer isProcessed) {
return delayDao.batchUpdateProcessedStatus(idList, isProcessed) > 0;
}
}
\ No newline at end of file
package com.wangxiaolu.promotion.service.wechat;
import com.wangxiaolu.promotion.domain.user.mapper.entity.WxTemporaryInfoDelayDO;
import com.wangxiaolu.promotion.pojo.activity.temporary.dto.WxTemporaryInfoDelayDtO;
import com.wangxiaolu.promotion.pojo.user.dto.WxTemporaryInfoDto;
import java.util.List;
/**
* @author : liqiulin
* @date : 2024-04-08 16
......@@ -21,4 +25,10 @@ public interface WeChatUserCoreService {
*/
boolean saveWxUserStoreInfoTemporary(WxTemporaryInfoDto temporaryDto);
boolean batchSaveWxUserStoreInfo(List<WxTemporaryInfoDto> list);
/**
* 保存延迟数据
*/
boolean saveDelayData(WxTemporaryInfoDelayDtO delayEntity);
}
......@@ -26,6 +26,6 @@ public interface WeChatUserQueryService {
*/
String findUserPhoneByID(Long temporaryId);
Object findTemporaryWorkStore(String openId);
Map<String,Object> findTemporaryWorkStore(String openId,String date);
}
......@@ -5,13 +5,16 @@ import com.wangxiaolu.promotion.domain.user.dao.QinCeEmployeeDao;
import com.wangxiaolu.promotion.domain.user.dao.TemporaryInfoDao;
import com.wangxiaolu.promotion.exception.ParamException;
import com.wangxiaolu.promotion.pojo.activity.temporary.dto.QinCeEmployeeDto;
import com.wangxiaolu.promotion.pojo.activity.temporary.dto.WxTemporaryInfoDelayDtO;
import com.wangxiaolu.promotion.pojo.user.dto.WxTemporaryInfoDto;
import com.wangxiaolu.promotion.result.basedata.RCode;
import com.wangxiaolu.promotion.service.user.WxTemporaryInfoDelayService;
import com.wangxiaolu.promotion.service.wechat.WeChatUserCoreService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
/**
......@@ -29,6 +32,9 @@ public class WeChatUserCoreServiceImpl implements WeChatUserCoreService {
@Autowired
QinCeEmployeeDao qinCeEmployeeDao;
@Autowired
private WxTemporaryInfoDelayService wxTemporaryInfoDelayService;
/**
* 保存促销员用户信息
*/
......@@ -52,4 +58,15 @@ public class WeChatUserCoreServiceImpl implements WeChatUserCoreService {
int saveId = temporaryInfoDao.saveWxUserStoreInfoTemporary(wxTemporaryInfoDto);
return saveId > 0;
}
@Override
public boolean batchSaveWxUserStoreInfo(List<WxTemporaryInfoDto> list) {
// 调用DAO批量插入/更新(含storeCode/dataDate)
return temporaryInfoDao.batchInsertOrUpdate(list) > 0;
}
@Override
public boolean saveDelayData(WxTemporaryInfoDelayDtO delayEntity) {
return wxTemporaryInfoDelayService.saveDelayData(delayEntity);
}
}
......@@ -71,7 +71,7 @@ public class WeChatUserQueryServiceImpl implements WeChatUserQueryService {
@Override
public LoginVo temporaryLoginByPhone(String phone) {
WxTemporaryInfoDto temDto = temporaryInfoDao.selectByPhone(phone);
WxTemporaryInfoDto temDto = temporaryInfoDao.selectOneByOpenId(phone);
if (Objects.isNull(temDto)) {
throw new DataException(RCode.LOGIN_USER_IS_NULL_ERROR);
}
......@@ -101,12 +101,7 @@ public class WeChatUserQueryServiceImpl implements WeChatUserQueryService {
}
@Override
public Map<String,String> findTemporaryWorkStore(String openId) {
WxTemporaryInfoDto wxTemporaryInfoDto = temporaryInfoDao.selectOneByOpenId(openId);
HashMap<String, String> resultMap = new HashMap<>();
resultMap.put("storeCode",wxTemporaryInfoDto.getStoreCode());
resultMap.put("storeName",wxTemporaryInfoDto.getStoreName());
return resultMap;
public Map<String,Object> findTemporaryWorkStore(String openId,String date) {
return temporaryInfoDao.selectStoreAndPlan(openId,date);
}
}
......@@ -284,24 +284,24 @@ public class TencentMapUtil {
return regionList;
}
// ==================== 缓存预热 ====================
@PostConstruct
public void preloadCache() {
// 预热三级区划缓存
new Thread(() -> {
try {
List<RegionNode> regionList = getTripleLevelRegion();
if (!regionList.isEmpty()) {
stringRedisTemplate.opsForValue().set(
"promotion:district:triple_level",
GSON.toJson(regionList),
86400L,
TimeUnit.SECONDS
);
}
} catch (Exception e) {
System.err.println("三级区划缓存预热失败:" + e.getMessage());
}
}).start();
}
// // ==================== 缓存预热 ====================
// @PostConstruct
// public void preloadCache() {
// // 预热三级区划缓存
// new Thread(() -> {
// try {
// List<RegionNode> regionList = getTripleLevelRegion();
// if (!regionList.isEmpty()) {
// stringRedisTemplate.opsForValue().set(
// "promotion:district:triple_level",
// GSON.toJson(regionList),
// 86400L,
// TimeUnit.SECONDS
// );
// }
// } catch (Exception e) {
// System.err.println("三级区划缓存预热失败:" + e.getMessage());
// }
// }).start();
// }
}
\ No newline at end of file
package com.wangxiaolu.promotion.xxljobtask;
import com.wangxiaolu.promotion.pojo.activity.temporary.dto.WxTemporaryInfoDelayDtO;
import com.wangxiaolu.promotion.pojo.user.dto.WxTemporaryInfoDto;
import com.wangxiaolu.promotion.service.wechat.WeChatUserCoreService;
import com.wangxiaolu.promotion.service.user.WxTemporaryInfoDelayService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* XXL-Job定时任务:每天00:01处理微信用户延迟更新的门店信息
* @author: 自定义
* @date: 2026-01-14
*/
@Slf4j
@Component
public class WxTemporaryInfoDelayHandler{
@Resource
private WxTemporaryInfoDelayService wxTemporaryInfoDelayService;
@Resource
private WeChatUserCoreService weChatUserCoreService;
/**
* 定时任务执行方法
* 任务描述:每天00:01处理前一天未处理的用户门店信息更新
* XXL-Job配置:cron表达式 0 1 0 * * ? (每天00:01执行)
*/
@XxlJob("wxTemporaryInfoDelayHandler")
public void execute() {
// 1. 任务日志记录(XXL-Job控制台可见)
XxlJobHelper.log("开始执行微信用户延迟信息更新任务,执行时间:{}", LocalDateTime.now());
try {
// 2. 构建时间范围:查询前一天00:00到当天00:00的未处理数据
LocalDate yesterday = LocalDate.now().minusDays(1);
LocalDateTime startTime = LocalDateTime.of(yesterday, LocalTime.MIN);
LocalDateTime endTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
// 3. 查询未处理的延迟数据
List<WxTemporaryInfoDelayDtO> unprocessedList = wxTemporaryInfoDelayService.listUnprocessedData(startTime, endTime);
if (unprocessedList == null || unprocessedList.isEmpty()) {
XxlJobHelper.log("未查询到需要处理的延迟数据,任务结束");
return;
}
XxlJobHelper.log("查询到待处理延迟数据共{}条", unprocessedList.size());
// 4. 转换DTO并批量更新门店信息
List<WxTemporaryInfoDto> updateList = new ArrayList<>();
List<Long> idList = new ArrayList<>();
for (WxTemporaryInfoDelayDtO delayDto : unprocessedList) {
// 4.1 收集需要标记为已处理的ID
idList.add(delayDto.getId());
// 4.2 转换为业务层需要的DTO
WxTemporaryInfoDto tempDto = new WxTemporaryInfoDto();
BeanUtils.copyProperties(delayDto, tempDto);
updateList.add(tempDto);
}
// 5. 批量更新用户门店信息
boolean updateResult = weChatUserCoreService.batchSaveWxUserStoreInfo(updateList);
if (!updateResult) {
XxlJobHelper.log("批量更新用户门店信息失败,数据量:{}", updateList.size());
XxlJobHelper.handleFail("批量更新用户门店信息失败");
return;
}
XxlJobHelper.log("批量更新用户门店信息成功,数据量:{}", updateList.size());
// 6. 标记延迟表数据为已处理(1=已处理)
boolean markResult = wxTemporaryInfoDelayService.batchUpdateProcessedStatus(idList, 1);
if (!markResult) {
XxlJobHelper.log("标记延迟数据为已处理失败,ID列表:{}", idList);
XxlJobHelper.handleFail("标记延迟数据为已处理失败");
return;
}
XxlJobHelper.log("标记{}条延迟数据为已处理成功", idList.size());
// 7. 任务执行成功
XxlJobHelper.handleSuccess("微信用户延迟信息更新任务执行成功,共处理" + unprocessedList.size() + "条数据");
} catch (Exception e) {
// 8. 异常处理
log.error("微信用户延迟信息更新任务执行异常", e);
XxlJobHelper.log("任务执行异常:{}", e.getMessage());
XxlJobHelper.handleFail("任务执行异常:" + e.getMessage());
}
}
}
\ No newline at end of file
......@@ -18,6 +18,8 @@
<result property="idenReversePhotoFieldId" column="iden_reverse_photo_field_id" jdbcType="VARCHAR"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
<result property="modifyTime" column="modify_time" jdbcType="TIMESTAMP"/>
<result property="storeName" column="store_name" jdbcType="VARCHAR"/>
<result property="storeCode" column="store_code" jdbcType="VARCHAR"/>
</resultMap>
<sql id="Base_Column_List">
......@@ -37,4 +39,23 @@
select <include refid="Base_Column_Unimportant"/> from temporary_info where open_id = #{openId}
</select>
<insert id="batchInsertOrUpdate">
INSERT INTO temporary_info (
open_id, store_name, store_code, data_date,
create_time, modify_time
) VALUES
<foreach collection="list" item="item" separator=",">
(
#{item.openId}, #{item.storeName}, #{item.storeCode}, #{item.dataDate},
NOW(), NOW()
)
</foreach>
<!-- 仅更新需要的字段,不覆盖原有核心字段(name/phone/idenNumber等) -->
ON DUPLICATE KEY UPDATE
store_name = VALUES(store_name), <!-- 仅更新门店名称 -->
store_code = VALUES(store_code), <!-- 仅更新门店编码 -->
modify_time = NOW() <!-- 仅更新修改时间 -->
</insert>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wangxiaolu.promotion.domain.user.mapper.WxTemporaryInfoDelayMapper">
<!-- 核心:resultMap映射(适配已有实体类WxTemporaryInfoDelay) -->
<resultMap id="WxTemporaryInfoDelayResultMap" type="com.wangxiaolu.promotion.domain.user.mapper.entity.WxTemporaryInfoDelayDO">
<id column="id" property="id"/> <!-- 主键映射 -->
<result column="open_id" property="openId"/> <!-- 数据库下划线 → Java驼峰 -->
<result column="store_name" property="storeName"/>
<result column="store_address" property="storeAddress"/>
<result column="contact_phone" property="contactPhone"/>
<result column="create_time" property="createTime"/>
<result column="is_processed" property="isProcessed"/>
<result column="update_time" property="updateTime"/>
</resultMap>
<!-- 查询指定时间范围未处理的数据(使用resultMap) -->
<select id="selectByTimeAndStatus" resultMap="WxTemporaryInfoDelayResultMap">
SELECT
id, open_id, store_name, store_address, contact_phone,
create_time, is_processed, update_time
FROM wx_temporary_info_delay
WHERE create_time BETWEEN #{startTime} AND #{endTime}
AND is_processed = #{isProcessed}
</select>
<!-- 批量更新处理状态 -->
<update id="batchUpdateStatus">
UPDATE wx_temporary_info_delay
SET is_processed = #{isProcessed}, update_time = NOW()
WHERE id IN
<foreach collection="idList" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</update>
<!-- 单条插入(适配已有实体,可选:MyBatis-Plus也可自动生成) -->
<insert id="insert" parameterType="com.wangxiaolu.promotion.domain.user.mapper.entity.WxTemporaryInfoDelayDO">
INSERT INTO wx_temporary_info_delay (
open_id, store_name, store_address, contact_phone,
create_time, is_processed, update_time
) VALUES (
#{openId}, #{storeName}, #{storeAddress}, #{contactPhone},
NOW(), 0, NOW()
)
</insert>
</mapper>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论