Merge #31 into master from cc_2021104_twelve_points

十二分

* cc_2021104_twelve_points: (34 commits squashed)

  - fix:启用禁用规则合并

  - Merge branch 'refs/heads/master' into cc_2021104_twelve_points

  - fix:惩处规则列表新增描述字段

  - fix:新增用户管辖门店列表接口

  - fix:门店列表接口新增门店积分字段

  - fix:查询问题修复;新增草稿状态

  - fix:申请单审批补充审批人字段

  - fix:修改门店积分限制0-12

  - fix:积分流水接口修复;申请单查询接口添加日期筛选

  - fix:惩处单查询提供惩处待处理、惩处已处理状态筛选

  - fix:惩处单复议申请查询异常修复

  - fix:小程序惩处单详情接口字段补充

  - fix:查询字段补充

  - fix

  - fix:转义

  - fix

  - fix:新增撤销复议申请单接口

  - fix:补充字段

  - fix:补充字段

  - fix:新增门店分数接口

  - fix:申请单新增筛选条件

  - fix:门店积分接口返回参数修改

  - fix:小程序规则分页查询接口改为Post

  - fix:问题修复

  - fix:十二分导入

  - fix:导入状态部分失败改为失败

  - fix:字段补充

  - fix:异步下Excel导入图片临时文件被清理的问题

  - fix:扣分申请导入图片路径修改并使用CDN

  - fix:导入图片上传oss文件类型修改为图片

  - fix:批量审批

  - fix:批量审批新增备注字段

  - fix:字段补充

  - Merge branch 'master' into cc_2021104_twelve_points
    
    # Conflicts:
    #	coolstore-partner-common/src/main/java/com/cool/store/constants/RedisConstant.java
    #	coolstore-partner-common/src/main/java/com/cool/store/enums/ErrorCodeEnum.java
    #	coolstore-partner-dao/src/main/java/com/cool/store/dao/StoreDao.java
    #	coolstore-partner-dao/src/main/java/com/cool/store/mapper/StoreMapper.java
    #	coolstore-partner-dao/src/main/resources/mapper/StoreMapper.xml
    #	coolstore-partner-web/src/main/java/com/cool/store/controller/webb/PCStoreController.java

Signed-off-by: 王非凡 <accounts_67eba0c5fee9c49c80c8e2b4@mail.teambition.com>
Reviewed-by: 正新 <accounts_6964c7bcd2a2c377c5bbd01b@mail.teambition.com>
Merged-by: 正新 <accounts_6964c7bcd2a2c377c5bbd01b@mail.teambition.com>

CR-link: https://codeup.aliyun.com/692ea314dec569489f6f167c/hangzhou/java/custom_zxjp/change/31
This commit is contained in:
王非凡
2026-01-23 06:48:53 +00:00
committed by 正新
parent 1b1684f373
commit 41ae24478d
39 changed files with 998 additions and 46 deletions

View File

@@ -1,5 +1,6 @@
package com.cool.store.oss;
import cn.hutool.core.date.DateUtil;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
@@ -13,6 +14,7 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.io.InputStream;
import java.util.Date;
/**
* Created by gavin on 15/8/5.
@@ -33,6 +35,10 @@ public class OssClientService {
@Value("${oss.host}")
private String ossHost;
@Value("${cdn.url:null}")
private String cdnUrl;
@Value("${oss.file.dir:null}")
private String dir;
private OSSClient client = null;
@@ -146,6 +152,11 @@ public class OssClientService {
putObject(fileName, inputStream, contentLength, contentType);
}
public String putObjectWithoutPrefix(String fileName, InputStream inputStream, Long contentLength, String contentType) throws Exception {
String time = DateUtil.format(new Date(), "yyMM");
return putObject(dir + time + "/" + fileName, inputStream, contentLength, contentType);
}
/**
* 上传文件到阿里云OSS
*
@@ -167,7 +178,7 @@ public class OssClientService {
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, inputStream, meta);
log.info("uploadBaseImage, send...");
PutObjectResult p = ossClient.putObject(putObjectRequest.withProgressListener(new PutObjectProgressListener()));
String url = "https://"+bucketName+"."+endpoint +"/"+ fileName;
String url = cdnUrl + fileName;
log.info("uploadBaseImage, send overurl:{}", url);
return url;

View File

@@ -0,0 +1,61 @@
package com.cool.store.request.tp;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* 扣分申请单导入行 DTO不含图片列
* 第1行为说明忽略
* 第2行为表头
* 从第3行开始为数据行
* A 门店编码
* B 惩处规则编码
* C 扣分分值
* D 罚款金额
* E 复议申请时效(天)
* F 备注
* G~L 证明图片1~6由监听器处理
*/
@Data
public class TpPenaltyImportRowDTO {
/**
* 门店编码
*/
@ExcelProperty(index = 0)
private String storeNum;
/**
* 惩处规则编码
*/
@ExcelProperty(index = 1)
private String ruleNo;
/**
* 扣分分值
*/
@ExcelProperty(index = 2)
private BigDecimal score;
/**
* 罚款金额
*/
@ExcelProperty(index = 3)
private BigDecimal amount;
/**
* 复议申请时效(天)
*/
@ExcelProperty(index = 4)
private Integer AppealDeadline;
/**
* 备注
*/
@ExcelProperty(index = 5)
private String remark;
}

View File

@@ -4,7 +4,9 @@ import com.cool.store.dto.StoreDTO;
import com.cool.store.dto.StoreNameDTO;
import com.cool.store.dto.store.AuthStoreUserDTO;
import com.cool.store.dto.store.StoreUserPositionDTO;
import com.cool.store.request.store.StoreListRequest;
import com.cool.store.response.MiniShopsResponse;
import com.cool.store.vo.store.StoreListVO;
import com.github.pagehelper.PageInfo;
import java.util.List;
@@ -42,4 +44,9 @@ public interface StoreService {
List<String> groupIdList,
List<String> regionIdList);
/**
* 获取当前用户权限区域下的门店列表
*/
PageInfo<StoreListVO> getAuthStoreList(StoreListRequest request);
}

View File

@@ -1,10 +1,10 @@
package com.cool.store.service.impl;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.context.CurrentUserHolder;
import com.cool.store.dto.StoreNameDTO;
import com.cool.store.dao.store.StoreMasterSignerInfoDAO;
import com.cool.store.dto.store.AuthStoreUserDTO;
@@ -21,11 +21,14 @@ import com.cool.store.entity.store.StoreMasterSignerInfoDO;
import com.cool.store.enums.*;
import com.cool.store.exception.ServiceException;
import com.cool.store.mapper.*;
import com.cool.store.request.store.StoreListRequest;
import com.cool.store.response.MiniShopsResponse;
import com.cool.store.service.StoreService;
import com.cool.store.service.UserAuthMappingService;
import com.cool.store.utils.BeanUtil;
import com.cool.store.utils.poi.constant.Constants;
import com.cool.store.vo.SysRoleVO;
import com.cool.store.vo.store.StoreListVO;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
@@ -38,6 +41,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -281,6 +285,29 @@ public class StoreServiceImpl implements StoreService {
return authStoreUsers;
}
@Override
public PageInfo<StoreListVO> getAuthStoreList(StoreListRequest request) {
String userId = CurrentUserHolder.getUserId();
List<String> regionIds = null;
Boolean isAdmin = enterpriseUserRoleDao.checkIsAdmin(userId);
if (!isAdmin) {
List<UserAuthMappingDO> userAuthMappings = userAuthMappingService.listUserAuthMappingByUserId(userId);
if (CollectionUtils.isEmpty(userAuthMappings)) {
return new PageInfo<>(Collections.emptyList());
}
regionIds = CollStreamUtil.toList(userAuthMappings, UserAuthMappingDO::getMappingId);
}
PageHelper.startPage(request.getPageNum(), request.getPageSize());
List<StoreDO> storeList = storeDao.getStoreByRegionIds(regionIds, request.getKeyword());
List<String> storeIds = CollStreamUtil.toList(storeList, StoreDO::getStoreId);
Map<String, BigDecimal> scoreMap = storeDao.getScoreByStoreIds(storeIds);
PageInfo<StoreListVO> page = BeanUtil.toPage(new PageInfo<>(storeList), StoreListVO.class);
page.getList().forEach(v -> {
v.setScore(scoreMap.getOrDefault(v.getStoreId(), new BigDecimal(12)));
});
return page;
}
@Override

View File

@@ -9,6 +9,7 @@ import com.cool.store.vo.tp.mini.MiniTpPenaltyApplyVO;
import com.cool.store.vo.tp.mini.MiniTpRewardApplyVO;
import com.cool.store.vo.tp.mini.MiniTpRuleListVO;
import com.github.pagehelper.PageInfo;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@@ -162,9 +163,37 @@ public interface TpApplyService {
*/
Boolean completePayment(Long applyId);
/**
* 撤销复议申请
* @param applyId 复议申请id
* @return 是否成功
*/
Boolean withdrawAppeal(Long applyId);
/**
* 积分变动
* @param formDO 申请单DO
*/
void scoreChange(TpApplyFormDO formDO);
/**
* 惩处申请单Excel导入异步执行立即返回
*
* @param file Excel 文件
*/
Boolean penaltyImport(MultipartFile file);
/**
* 门店积分
* @param storeId 门店id
* @return 积分
*/
TpStoreScoreVO getStoreScore(String storeId);
/**
* 批量审批
* @param request 申请单批量审批Request
* @return 申请单批量审批结果VO列表
*/
List<TpBatchAuditVO> batchAudit(TpBatchAuditRequest request);
}

View File

@@ -1,28 +1,38 @@
package com.cool.store.service.tp.impl;
import cn.hutool.core.collection.CollStreamUtil;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.constants.CommonConstants;
import com.cool.store.constants.RedisConstant;
import com.cool.store.context.CurrentUserHolder;
import com.cool.store.context.LoginUserInfo;
import com.cool.store.dao.EnterpriseUserDAO;
import com.cool.store.dao.StoreDao;
import com.cool.store.dao.tp.*;
import com.cool.store.dto.ImportOaOldShopDataErrorDTO;
import com.cool.store.dto.tp.TpPenaltyImportErrorDTO;
import com.cool.store.entity.ImportTaskDO;
import com.cool.store.entity.StoreDO;
import com.cool.store.entity.tp.TpApplyFormDO;
import com.cool.store.entity.tp.TpRuleDO;
import com.cool.store.entity.tp.TpScoreJournalDO;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.enums.FileTypeEnum;
import com.cool.store.enums.ImportTaskStatusEnum;
import com.cool.store.enums.tp.TpFormStatusEnum;
import com.cool.store.enums.tp.TpFormTypeEnum;
import com.cool.store.enums.tp.TpPayStatusEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.mapper.ImportTaskMapper;
import com.cool.store.oss.OssClientService;
import com.cool.store.request.tp.*;
import com.cool.store.response.AuditInfoResponse;
import com.cool.store.service.dict.impl.DictService;
import com.cool.store.service.tp.TpApplyService;
import com.cool.store.utils.BeanUtil;
import com.cool.store.utils.CoolDateUtils;
import com.cool.store.utils.TpHelper;
import com.cool.store.request.tp.TpPenaltyImportRowDTO;
import com.cool.store.utils.*;
import com.cool.store.utils.easyExcel.EasyExcelUtil;
import com.cool.store.utils.poi.DateUtils;
import com.cool.store.vo.tp.*;
import com.cool.store.vo.tp.mini.*;
import com.github.pagehelper.PageHelper;
@@ -30,13 +40,24 @@ import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.excel.EasyExcel;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import static com.cool.store.utils.poi.DateUtils.SPECIAL_DATE_START_1;
/**
* <p>
@@ -58,6 +79,14 @@ public class TpApplyServiceImpl implements TpApplyService {
private final DictService dictService;
private final TpScoreJournalDAO tpScoreJournalDAO;
private final EnterpriseUserDAO enterpriseUserDAO;
private final RedisUtilPool redisUtilPool;
private final OssClientService ossClientService;
private final ImportTaskMapper importTaskMapper;
@Resource(name = "generalThreadPool")
private ThreadPoolTaskExecutor executor;
private final EasyExcelUtil easyExcelUtil;
@Value("${mybatis.configuration.variables.enterpriseId}")
private String eid;
@Override
@Transactional
@@ -81,6 +110,7 @@ public class TpApplyServiceImpl implements TpApplyService {
formDO.setType(TpFormTypeEnum.REWARD.getType());
formDO.setPayStatus(TpPayStatusEnum.NO_NEED_PAY.getStatus());
}
formDO.setStatus(isDraft ? TpFormStatusEnum.DRAFT.getStatus() : TpFormStatusEnum.PENDING.getStatus());
fillRuleFields(formDO);
tpApplyFormDAO.insertOrUpdate(formDO);
// 第一次提交后添加审批记录
@@ -126,6 +156,7 @@ public class TpApplyServiceImpl implements TpApplyService {
throw new ServiceException(ErrorCodeEnum.TP_EXISTS_PENDING_APPLY);
}
fillRuleFields(formDO);
formDO.setStatus(isDraft ? TpFormStatusEnum.DRAFT.getStatus() : TpFormStatusEnum.PENDING.getStatus());
formDO.setApplyNo(Objects.isNull(request.getId()) ? TpHelper.generateApplyNo(formDO.getType()) : null);
tpApplyFormDAO.insertOrUpdate(formDO);
// 第一次提交后添加审批记录
@@ -171,7 +202,7 @@ public class TpApplyServiceImpl implements TpApplyService {
if (!TpFormStatusEnum.PENDING.getStatus().equals(formDO.getStatus())) {
throw new ServiceException(ErrorCodeEnum.TP_APPLY_AUDIT_COMPLETED);
}
if (tpApplyFormDAO.existPassRewardForm(formDO.getStoreId(), formDO.getRuleId())) {
if (CommonConstants.INDEX_ONE.equals(request.getAuditStatus()) && tpApplyFormDAO.existPassRewardForm(formDO.getStoreId(), formDO.getRuleId())) {
throw new ServiceException(ErrorCodeEnum.TP_MONTH_EXIST_APPLY);
}
auditCommon(request, formDO);
@@ -220,6 +251,7 @@ public class TpApplyServiceImpl implements TpApplyService {
formDO.setRuleId(penaltyFormDO.getRuleId());
formDO.setType(TpFormTypeEnum.APPEAL.getType());
formDO.setStoreId(penaltyFormDO.getStoreId());
formDO.setStatus(isDraft ? TpFormStatusEnum.DRAFT.getStatus() : TpFormStatusEnum.PENDING.getStatus());
fillRuleFields(formDO);
tpApplyFormDAO.insertOrUpdate(formDO);
// 第一次提交后添加审批记录
@@ -307,7 +339,9 @@ public class TpApplyServiceImpl implements TpApplyService {
@Override
public MiniTpRewardApplyVO getMiniRewardApplyDetail(Long applyId) {
TpApplyFormDO formDO = tpApplyFormDAO.getEffectiveById(applyId);
return BeanUtil.toBean(formDO, MiniTpRewardApplyVO.class);
MiniTpRewardApplyVO vo = BeanUtil.toBean(formDO, MiniTpRewardApplyVO.class);
dictService.fillDictField(vo);
return vo;
}
@Override
@@ -315,7 +349,7 @@ public class TpApplyServiceImpl implements TpApplyService {
TpApplyFormDO formDO = tpApplyFormDAO.getEffectiveById(applyId);
if (Objects.nonNull(formDO)) {
MiniTpPenaltyApplyVO vo = BeanUtil.toBean(formDO, MiniTpPenaltyApplyVO.class);
TpApplyFormDO appealForm = tpApplyFormDAO.getAppealByPenaltyId(formDO.getPenaltyId());
TpApplyFormDO appealForm = tpApplyFormDAO.getAppealByPenaltyId(formDO.getId());
vo.setAppeal(BeanUtil.toBean(appealForm, MiniTpAppealVO.class));
dictService.fillDictField(vo);
return vo;
@@ -366,6 +400,19 @@ public class TpApplyServiceImpl implements TpApplyService {
return true;
}
@Override
public Boolean withdrawAppeal(Long applyId) {
TpApplyFormDO formDO = tpApplyFormDAO.getById(applyId);
if (Objects.isNull(formDO) || !TpFormTypeEnum.APPEAL.getType().equals(formDO.getType())) {
throw new ServiceException(ErrorCodeEnum.TP_NOT_EXIST_APPLY_FORM);
}
if (!TpFormStatusEnum.PENDING.getStatus().equals(formDO.getStatus()) && !TpFormStatusEnum.DRAFT.getStatus().equals(formDO.getStatus())) {
throw new ServiceException(ErrorCodeEnum.TP_APPLY_AUDIT_COMPLETED);
}
tpApplyFormDAO.deleteByIds(Collections.singletonList(applyId));
return true;
}
/**
* 审批通用方法
*/
@@ -374,6 +421,7 @@ public class TpApplyServiceImpl implements TpApplyService {
// 修改申请单审批数据
formDO.setStatus(CommonConstants.INDEX_ONE.equals(request.getAuditStatus()) ? TpFormStatusEnum.PASS.getStatus() : TpFormStatusEnum.REJECT.getStatus());
formDO.setApproveTime(now);
formDO.setApproveUserId(CurrentUserHolder.getUserId());
tpApplyFormDAO.updateSelective(formDO);
LoginUserInfo user = CurrentUserHolder.getUser();
// 处理审批记录
@@ -420,6 +468,13 @@ public class TpApplyServiceImpl implements TpApplyService {
}
// 修改门店积分
if (Objects.nonNull(occurAfterScore)) {
// 限制积分在0-12之间
if (occurAfterScore.compareTo(BigDecimal.valueOf(12)) > 0) {
occurAfterScore = BigDecimal.valueOf(12);
}
if (occurAfterScore.compareTo(BigDecimal.ZERO) < 0) {
occurAfterScore = BigDecimal.ZERO;
}
storeDao.updateStoreScore(formDO.getStoreId(), occurAfterScore);
StoreDO storeDO = storeDao.getEffectiveByStoreId(formDO.getStoreId());
if (Objects.isNull(storeDO)) {
@@ -431,6 +486,124 @@ public class TpApplyServiceImpl implements TpApplyService {
}
}
@Override
public TpStoreScoreVO getStoreScore(String storeId) {
StoreDO storeDO = storeDao.getEffectiveByStoreId(storeId);
BigDecimal score = storeDao.getStoreScore(storeId);
return new TpStoreScoreVO(storeDO.getStoreName(), storeDO.getAvatar(), score);
}
@Override
@Transactional
public List<TpBatchAuditVO> batchAudit(TpBatchAuditRequest request) {
List<TpBatchAuditVO> result = new ArrayList<>();
TpFormTypeEnum type = TpFormTypeEnum.getByType(request.getType());
if (Objects.isNull(type)) {
throw new ServiceException(ErrorCodeEnum.TP_NOT_EXIST_FORM_TYPE);
}
for (Long applyId : request.getApplyIds()) {
boolean f = false;
String failReason = null;
try {
switch (type) {
case REWARD:
f = rewardAudit(new TpApplyAuditRequest(applyId, request.getAuditStatus(), request.getRemark()));
break;
case PENALTY:
case WARNING:
f = penaltyAudit(new TpApplyAuditRequest(applyId, request.getAuditStatus(), request.getRemark()));
break;
case APPEAL:
f = appealAudit(new TpApplyAuditRequest(applyId, request.getAuditStatus(), request.getRemark()));
break;
}
if (!f) {
failReason = "未知错误,请联系管理员";
}
} catch (ServiceException e) {
failReason = e.getErrorMessage();
} catch (Exception e) {
failReason = "未知错误,请联系管理员";
log.error("申请单批量审批失败applyId:{}", applyId, e);
}
result.add(new TpBatchAuditVO(applyId, f ? 1 : 2, failReason));
}
List<Long> applyIds = CollStreamUtil.toList(result, TpBatchAuditVO::getApplyId);
List<TpApplyFormDO> forms = tpApplyFormDAO.getByIds(applyIds);
Map<Long, String> applyNoMap = CollStreamUtil.toMap(forms, TpApplyFormDO::getId, TpApplyFormDO::getApplyNo);
result.forEach(v -> v.setApplyNo(applyNoMap.get(v.getApplyId())));
return result;
}
/**
* 惩处申请单Excel导入异步执行立即返回
*/
@Override
public Boolean penaltyImport(MultipartFile file) {
final String lockKey = RedisConstant.TP_PENALTY_APPLY_IMPORT_LOCK;
boolean lock = redisUtilPool.setNxExpire(lockKey, UUIDUtils.get32UUID(), 30 * 60 * 1000);
if (!lock) {
throw new ServiceException(ErrorCodeEnum.TP_EXIST_PENDING_IMPORT_TASK);
}
ImportTaskDO importTaskDO = new ImportTaskDO();
importTaskDO.setFileName(file.getOriginalFilename());
importTaskDO.setFileType(FileTypeEnum.TP_PENALTY_IMPORT.getFileType());
importTaskDO.setIsImport(true);
importTaskDO.setStatus(ImportTaskStatusEnum.PROGRESS.getCode());
importTaskDO.setCreateUserId(CurrentUserHolder.getUserId());
importTaskDO.setCreateName(CurrentUserHolder.getUser().getName());
importTaskDO.setCreateTime(System.currentTimeMillis());
importTaskMapper.insert(eid, importTaskDO);
LoginUserInfo user = CurrentUserHolder.getUser();
try {
// 图片是额外读取文件操作,这里使用异步会导致临时文件被清理,因此改成字节数组传参
byte[] excelBytes = file.getBytes();
executor.execute(() -> importPenalty(excelBytes, importTaskDO, user));
} catch (Exception e) {
log.error("导入失败");
}
return true;
}
private void importPenalty(byte[] excelBytes, ImportTaskDO importTaskDO, LoginUserInfo user) {
List<TpPenaltyImportErrorDTO> errorList = new ArrayList<>();
AtomicInteger successNum = new AtomicInteger();
AtomicInteger totalNum = new AtomicInteger();
try {
EasyExcel.read(new ByteArrayInputStream(excelBytes), TpPenaltyImportRowDTO.class,
new TpPenaltyImportListener(this, tpRuleDAO, storeDao, ossClientService, errorList, user, excelBytes, totalNum, successNum))
.sheet(0)
.headRowNumber(2)
.doRead();
} catch (Exception e) {
log.error("惩处申请单导入失败", e);
} finally {
try {
final String lockKey = RedisConstant.TP_PENALTY_APPLY_IMPORT_LOCK;
String value = redisUtilPool.getString(lockKey);
if (StringUtils.isNotBlank(value)) {
redisUtilPool.delKey(lockKey);
}
} catch (Exception ex) {
log.error("释放惩处申请导入锁异常", ex);
}
}
importTaskDO.setStatus(totalNum.get() == successNum.get() ? ImportTaskStatusEnum.SUCCESS.getCode() : ImportTaskStatusEnum.ERROR.getCode());
importTaskDO.setTotalNum(totalNum.get());
importTaskDO.setSuccessNum(successNum.get());
if (CollectionUtils.isNotEmpty(errorList)) {
try {
String url = easyExcelUtil.exportExcel(ImportOaOldShopDataErrorDTO.class, errorList, null,
FileTypeEnum.TP_PENALTY_ERROR_EXPORT.getDesc() + DateUtils.parseDateToStr(SPECIAL_DATE_START_1, new Date()),
FileTypeEnum.TP_PENALTY_ERROR_EXPORT.getDesc() + DateUtils.parseDateToStr(SPECIAL_DATE_START_1, new Date()));
importTaskDO.setFileUrl(url);
} catch (Exception e) {
log.info("导出失败列表失败 errorList:{}", JSONObject.toJSONString(errorList));
}
}
importTaskMapper.update(eid, importTaskDO);
}
/**
* 填充规则相关字段
*/

View File

@@ -0,0 +1,208 @@
package com.cool.store.service.tp.impl;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.listener.ReadListener;
import com.cool.store.context.LoginUserInfo;
import com.cool.store.dao.StoreDao;
import com.cool.store.dao.tp.TpRuleDAO;
import com.cool.store.dto.tp.TpPenaltyImportErrorDTO;
import com.cool.store.entity.StoreDO;
import com.cool.store.entity.tp.TpRuleDO;
import com.cool.store.exception.ServiceException;
import com.cool.store.oss.OssClientService;
import com.cool.store.request.tp.TpApplyRequest;
import com.cool.store.request.tp.TpPenaltyImportRowDTO;
import com.cool.store.service.tp.TpApplyService;
import com.cool.store.utils.CoolDateUtils;
import com.cool.store.utils.UUIDUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.xssf.usermodel.*;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
* 扣分申请单导入监听器
*/
@RequiredArgsConstructor
@Slf4j
public class TpPenaltyImportListener implements ReadListener<TpPenaltyImportRowDTO> {
/**
* 证明图片起始列索引从0开始G列=6
*/
private static final int IMAGE_COL_START_INDEX = 6;
/**
* 证明图片结束列索引L列=11
*/
private static final int IMAGE_COL_END_INDEX = 11;
/**
* 每行最多图片数量
*/
private static final int MAX_IMAGE_PER_ROW = 6;
private final TpApplyService tpApplyService;
private final TpRuleDAO tpRuleDAO;
private final StoreDao storeDao;
private final OssClientService ossClientService;
private final List<TpPenaltyImportErrorDTO> errorList;
private final LoginUserInfo user;
private final byte[] excelBytes;
private final AtomicInteger totalNum;
private final AtomicInteger successNum;
private final Map<Integer, List<String>> pictureMap = new HashMap<>();
private volatile boolean pictureParsed = false;
@Override
public void onException(Exception e, AnalysisContext analysisContext) {
log.error("导入失败", e);
}
@Override
public void invokeHead(Map<Integer, CellData> map, AnalysisContext analysisContext) {
// head会回调多次图片解析只做一次
if (pictureParsed) {
return;
}
try {
XSSFWorkbook book = new XSSFWorkbook(new ByteArrayInputStream(excelBytes));
XSSFSheet sheet = book.getSheetAt(0);
if (Objects.isNull(sheet)) {
log.error("读取失败");
}
// 获取所有图片
XSSFDrawing drawingPatriarch = sheet.getDrawingPatriarch();
if (Objects.isNull(drawingPatriarch)) {
throw new RuntimeException("excel表格中没有图片请补充");
}
List<XSSFShape> shapes = drawingPatriarch.getShapes();
if (CollectionUtils.isEmpty(shapes)) {
log.info("表格中没有图片");
}
List<XSSFPicture> pictures = shapes.stream()
.filter(shape -> shape instanceof XSSFPicture)
.map(shape -> (XSSFPicture) shape)
.collect(Collectors.toList());
if (pictures.isEmpty()) {
return;
}
// 查找指定单元格中的图片
String fileNamePrefix = UUIDUtils.get32UUID();
for (XSSFPicture picture : pictures) {
ClientAnchor anchor = picture.getPreferredSize();
int row = anchor.getRow1();
int col = anchor.getCol1();
// 检查图片是否在指定单元格中
if (IMAGE_COL_START_INDEX <= col && col <= IMAGE_COL_END_INDEX) {
XSSFPictureData pictureData = picture.getPictureData();
byte[] data = pictureData.getData();
// 获取图片后缀
String fileName = fileNamePrefix + "-" + (row + 1) + "-" + (col + 1) + ".jpg";
try (InputStream in = new ByteArrayInputStream(data)) {
String url = ossClientService.putObjectWithoutPrefix(fileName, in, (long) data.length, "image/jpeg");
pictureMap.compute(row, (key, value) -> {
if (value == null) {
value = new ArrayList<>();
}
value.add(url);
return value;
});
} catch (Exception e) {
log.error("第{}行图片上传失败", row + 1, e);
}
}
}
pictureParsed = true;
} catch (Exception e) {
log.error("图片解析失败", e);
}
}
@Override
public void invoke(TpPenaltyImportRowDTO data, AnalysisContext context) {
totalNum.incrementAndGet();
int rowIndex = context.readRowHolder().getRowIndex();
// 基础必填校验
if (data == null) {
return;
}
if (data.getStoreNum() == null || data.getStoreNum().trim().isEmpty()) {
errorList.add(new TpPenaltyImportErrorDTO(data.getStoreNum(), data.getRuleNo(), "门店编码为空"));
return;
}
if (data.getRuleNo() == null || data.getRuleNo().trim().isEmpty()) {
errorList.add(new TpPenaltyImportErrorDTO(data.getStoreNum(), data.getRuleNo(), "行惩处规则编码为空"));
return;
}
// 根据门店编码查询门店
StoreDO store = storeDao.getByStoreNum(data.getStoreNum());
if (store == null) {
errorList.add(new TpPenaltyImportErrorDTO(data.getStoreNum(), data.getRuleNo(), "门店编码不存在"));
return;
}
// 根据规则编码查询规则
TpRuleDO rule = tpRuleDAO.getEnableByCode(data.getRuleNo());
if (rule == null) {
errorList.add(new TpPenaltyImportErrorDTO(data.getStoreNum(), data.getRuleNo(), "惩处规则编码不存在"));
return;
}
TpApplyRequest request = new TpApplyRequest();
request.setStoreId(store.getStoreId());
request.setRuleId(rule.getId());
request.setRemark(data.getRemark());
request.setIsDraft(0);
request.setSource(0);
request.setApplyUserId(user.getUserId());
request.setApplyUserName(user.getName());
List<String> proofUrls = pictureMap.getOrDefault(rowIndex, Collections.emptyList());
request.setProofUrls(String.join(",", proofUrls.subList(0, Math.min(proofUrls.size(), MAX_IMAGE_PER_ROW))));
request.setScore(data.getScore());
request.setAmount(data.getAmount());
if (Objects.nonNull(data.getAppealDeadline())) {
request.setAppealEndDate(CoolDateUtils.localDate2Date(LocalDate.now().plusDays(data.getAppealDeadline())));
}
try {
tpApplyService.penaltyApplySubmit(request);
successNum.incrementAndGet();
} catch (ServiceException e) {
errorList.add(new TpPenaltyImportErrorDTO(data.getStoreNum(), data.getRuleNo(), e.getErrorMessage()));
} catch (Exception e) {
log.error("申请单创建失败", e);
errorList.add(new TpPenaltyImportErrorDTO(data.getStoreNum(), data.getRuleNo(), "数据异常"));
}
}
@Override
public void extra(CellExtra cellExtra, AnalysisContext analysisContext) {
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// ignore
}
@Override
public boolean hasNext(AnalysisContext analysisContext) {
return true;
}
}