package cn.fw.morax.service.biz.eval; import cn.fw.common.data.mybatis.pagination.PageData; import cn.fw.common.exception.BusinessException; import cn.fw.common.page.AppPage; import cn.fw.common.web.auth.LoginAuthBean; import cn.fw.morax.common.pojo.event.ImportEvalIndicatorEvent; import cn.fw.morax.common.utils.EventBusUtil; import cn.fw.morax.common.utils.ExcelDataUtil; import cn.fw.morax.common.utils.PublicUtil; import cn.fw.morax.domain.db.eval.*; import cn.fw.morax.domain.dto.query.EvalIndicatorImportQueryDTO; import cn.fw.morax.domain.enums.DimensionTypeEnum; import cn.fw.morax.domain.enums.ImportErrorReasonEnum; import cn.fw.morax.domain.enums.SettingStatusEnum; import cn.fw.morax.domain.vo.eval.*; import cn.fw.morax.service.biz.CommonService; import cn.fw.morax.service.data.eval.*; import cn.hutool.poi.excel.ExcelReader; import cn.hutool.poi.excel.ExcelUtil; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.google.common.collect.Lists; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.map.MultiKeyMap; import org.apache.poi.ss.formula.functions.T; import org.checkerframework.checker.units.qual.K; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.BoundValueOperations; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; /** * @author jiangchao * @des: 考评指标上报 * @date 2023/2/8 17:04 */ @Service @Slf4j @RequiredArgsConstructor public class EvalIndicatorReportService { private final EvalIndicatorImportRecordService evalIndicatorImportRecordService; private final EvalIndicatorImportDetailService evalIndicatorImportDetailService; private final EvalIndicatorService evalIndicatorService; private final EvalUserPoolService evalUserPoolService; private final EvalShopPoolService evalShopPoolService; private final StringRedisTemplate stringRedisTemplate; private final EvalGroupService evalGroupService; private final EvalService evalService; @Value("${spring.cache.custom.global-prefix}:eval-import:") @Getter private String evalImport; @Value("${spring.cache.custom.global-prefix}:eval-import-detail:") @Getter private String evalImportDetail; public void staffTemplateFile(HttpServletRequest request, HttpServletResponse response) { String fileName = "人员导入标准模板.xlsx"; String encodeFileName = CommonService.getEncodeName(request, fileName); CommonService.downloadExcel(response, staffTemplateData(), encodeFileName, StaffIndicatorValueVO.class); } public void shopTemplateFile(HttpServletRequest request, HttpServletResponse response) { String fileName = "门店导入标准模板.xlsx"; String encodeFileName = CommonService.getEncodeName(request, fileName); CommonService.downloadExcel(response, shopTemplateData(), encodeFileName, ShopIndicatorValueVO.class); } /** * 分页查询 * * @param dto * @return */ public AppPage importPage(EvalIndicatorImportQueryDTO dto) { LocalDateTime startTime = (PublicUtil.isNotEmpty(dto.getStartTime())) ? LocalDateTime.of(dto.getStartTime(), LocalTime.MIN) : null; LocalDateTime endTime = (PublicUtil.isNotEmpty(dto.getEndTime())) ? LocalDateTime.of(dto.getEndTime(), LocalTime.MAX) : null; PageData pageData = evalIndicatorImportRecordService.page(new PageData<>(dto.getCurrent(), dto.getPageSize()), Wrappers.lambdaQuery() .eq(PublicUtil.isNotEmpty(dto.getUserId()), EvalIndicatorImportRecord::getImportUserId, dto.getUserId()) .eq(PublicUtil.isNotEmpty(dto.getIndicatorCode()), EvalIndicatorImportRecord::getIndicatorCode, dto.getIndicatorCode()) .ge(PublicUtil.isNotEmpty(startTime), EvalIndicatorImportRecord::getCreateTime, startTime) .le(PublicUtil.isNotEmpty(endTime), EvalIndicatorImportRecord::getCreateTime, endTime) .eq(EvalIndicatorImportRecord::getYn, Boolean.TRUE) .orderByDesc(EvalIndicatorImportRecord::getCreateTime) ); return PublicUtil.toPage(pageData, importRecord -> { EvalIndicatorImportRecordVO importRecordVO = PublicUtil.copy(importRecord, EvalIndicatorImportRecordVO.class); return importRecordVO; }); } public List importDetail(Long id, Boolean querySuccess) { LambdaQueryWrapper wrappers = Wrappers.lambdaQuery() .eq(EvalIndicatorImportDetail::getRecordId, id) .eq(EvalIndicatorImportDetail::getYn, Boolean.TRUE); if (PublicUtil.isNotEmpty(querySuccess)) { if (querySuccess) { wrappers.isNotNull("error_type"); }else { wrappers.isNull("error_type"); } } List details = evalIndicatorImportDetailService.list(wrappers); if (PublicUtil.isEmpty(details)) { return new ArrayList<>(); } List detailVOS = Lists.newArrayListWithCapacity(details.size()); for (EvalIndicatorImportDetail detail : details) { EvalIndicatorImportDetailVO detailVO = PublicUtil.copy(detail, EvalIndicatorImportDetailVO.class); detailVO.convertToPercent(); detailVOS.add(detailVO); } return detailVOS; } @Transactional(rollbackFor = Exception.class) public EvalIndicatorImportRecordVO uploadStaffIndicator(MultipartFile file, LoginAuthBean user) { MultiKeyMap staffPostMap = getShopUserPoolMap(user); Map evalIndicatorMap = getNameIndicatorMap(); EvalIndicatorImportRecord importRecord = createRecord(user, DimensionTypeEnum.STAFF); // evalIndicatorImportRecordService.save(importRecord); List details = new ArrayList<>(); List indicatorValues = this.analysisExcel(file, StaffIndicatorValueVO.class); Long importRecordId = importRecord.getId(); Integer errorNum = 0; Set uploadIndicatorCodes = new HashSet<>(); MultiKeyMap repeatMap = new MultiKeyMap<>(); for (StaffIndicatorValueVO staff : indicatorValues) { Optional valueOptional = Optional.ofNullable(staff); EvalIndicatorImportDetail importDetail = convertStaffPo(valueOptional); importDetail.setRecordId(importRecordId); details.add(importDetail); if (repeatMap.containsKey(staff.getStaffName(), staff.getShopName(), staff.getIndicatorName())) { importDetail.setErrorType(ImportErrorReasonEnum.NO_MATCH_STAFF); errorNum += 1; continue; } repeatMap.put(staff.getStaffName(), staff.getShopName(), staff.getIndicatorName(), ""); importDetail.setDataDate(transferDate(staff.getDataDate())); if (! staffPostMap.containsKey(staff.getShopName(), staff.getStaffName())) { importDetail.setErrorType(ImportErrorReasonEnum.NO_MATCH_STAFF); errorNum += 1; continue; } EvalUserPool userPool = staffPostMap.get(staff.getShopName(), staff.getStaffName()); importDetail.setUserId(userPool.getUserId()); importDetail.setShopId(userPool.getShopId()); if (! evalIndicatorMap.containsKey(staff.getIndicatorName())) { importDetail.setErrorType(ImportErrorReasonEnum.NO_MATCH_INDICATOR); errorNum += 1; continue; } EvalIndicator evalIndicator = evalIndicatorMap.get(staff.getIndicatorName()); uploadIndicatorCodes.add(evalIndicator.getCode()); importDetail.setIndicatorCode(evalIndicator.getCode()); importDetail.setIndicatorName(evalIndicator.getName()); importDetail.setIndicatorValue(new BigDecimal(staff.getIndicatorValue())); importDetail.setDataType(evalIndicator.getDataType()); } Optional detailOptional = details.stream().filter(detail -> PublicUtil.isEmpty(detail.getErrorType())).findFirst(); importRecord.setIndicatorCode(detailOptional.map(EvalIndicatorImportDetail::getIndicatorCode).orElse("")); importRecord.setIndicatorName(detailOptional.map(EvalIndicatorImportDetail::getIndicatorName).orElse("")); importRecord.setErrorNum(errorNum); importRecord.setNum(indicatorValues.size()); importRecord.setSuccessNum(indicatorValues.size() - errorNum); String key = PublicUtil.getUUID() + user.getUserId(); stringRedisTemplate.opsForValue().set(getEvalImport() + key, JSON.toJSONString(importRecord), 1 , TimeUnit.DAYS); stringRedisTemplate.opsForValue().set(getEvalImportDetail() + key, JSON.toJSONString(details), 1 , TimeUnit.DAYS); EvalIndicatorImportRecordVO recordVO = PublicUtil.copy(importRecord, EvalIndicatorImportRecordVO.class); List detailVos = PublicUtil.copyList(details, EvalIndicatorImportDetailVO.class); recordVO.setDetails(detailVos); recordVO.setKey(key); return recordVO; // evalIndicatorImportRecordService.updateById(importRecord); // evalIndicatorImportDetailService.saveBatch(details); // for (String indicatorCode : uploadIndicatorCodes) { // ImportEvalIndicatorEvent importEvalIndicatorEvent = new ImportEvalIndicatorEvent(indicatorCode, // importRecord.getId(), importRecord.getGroupId(), importRecord.getUploadTime()); // EventBusUtil.asyncPost(importEvalIndicatorEvent); // } } public void saveImportIndicator(String key) { BoundValueOperations importOperation = stringRedisTemplate.boundValueOps(getEvalImport() + key); BoundValueOperations importDetailOperation = stringRedisTemplate.boundValueOps(getEvalImportDetail() + key); String json = importOperation.get(); String detailJson = importDetailOperation.get(); if (PublicUtil.isEmpty(json) || PublicUtil.isEmpty(detailJson)) { log.error("考评指标导入,redis数据为空,key {},", getEvalImport() + key); throw new BusinessException("请求超时,请重新上传"); } EvalIndicatorImportRecord record = JSON.parseObject(json, EvalIndicatorImportRecord.class); List details = JSON.parseArray(detailJson, EvalIndicatorImportDetail.class); evalIndicatorImportRecordService.save(record); Long recordId = record.getId(); Set uploadIndicatorCodes = new HashSet<>(); for (EvalIndicatorImportDetail detail : details) { detail.setRecordId(recordId); if (PublicUtil.isEmpty(detail.getErrorType()) && PublicUtil.isEmpty(detail.getIndicatorCode())) { uploadIndicatorCodes.add(detail.getIndicatorCode()); } } evalIndicatorImportDetailService.saveBatch(details); stringRedisTemplate.delete(getEvalImport() + key); stringRedisTemplate.delete(getEvalImportDetail() + key); //事件 for (String indicatorCode : uploadIndicatorCodes) { ImportEvalIndicatorEvent importEvalIndicatorEvent = new ImportEvalIndicatorEvent(indicatorCode, recordId, record.getGroupId(), record.getUploadTime()); EventBusUtil.asyncPost(importEvalIndicatorEvent); } } @Transactional(rollbackFor = Exception.class) public EvalIndicatorImportRecordVO uploadShopIndicator(MultipartFile file, LoginAuthBean user) { Map shopPoolMap = this.getShopPoolMap(user); Map evalIndicatorMap = getNameIndicatorMap(); EvalIndicatorImportRecord importRecord = createRecord(user, DimensionTypeEnum.SHOP); // evalIndicatorImportRecordService.save(importRecord); Long importRecordId = importRecord.getId(); List details = new ArrayList<>(); List indicatorValues = this.analysisExcel(file, ShopIndicatorValueVO.class); Integer errorNum = 0; Set uploadIndicatorCodes = new HashSet<>(); MultiKeyMap repeatMap = new MultiKeyMap<>(); for (ShopIndicatorValueVO shop : indicatorValues) { Optional valueOptional = Optional.ofNullable(shop); EvalIndicatorImportDetail importDetail = convertShopPo(valueOptional); importDetail.setRecordId(importRecordId); details.add(importDetail); if (repeatMap.containsKey(shop.getShopName(), shop.getIndicatorName())) { importDetail.setErrorType(ImportErrorReasonEnum.NO_MATCH_STAFF); errorNum += 1; continue; } repeatMap.put(shop.getShopName(), shop.getIndicatorName(), ""); importDetail.setDataDate(transferDate(shop.getDataDate())); if (! shopPoolMap.containsKey(shop.getShopName())) { importDetail.setErrorType(ImportErrorReasonEnum.NO_MATCH_SHOP); errorNum += 1; continue; } EvalShopPool shopPool = shopPoolMap.get(shop.getShopName()); importDetail.setShopId(shopPool.getShopId()); if (! evalIndicatorMap.containsKey(shop.getIndicatorName())) { importDetail.setErrorType(ImportErrorReasonEnum.NO_MATCH_INDICATOR); errorNum += 1; continue; } EvalIndicator evalIndicator = evalIndicatorMap.get(shop.getIndicatorName()); uploadIndicatorCodes.add(evalIndicator.getCode()); importDetail.setIndicatorCode(evalIndicator.getCode()); importDetail.setIndicatorName(evalIndicator.getName()); importDetail.setIndicatorValue(new BigDecimal(shop.getIndicatorValue())); importDetail.setDataType(evalIndicator.getDataType()); } importRecord.setErrorNum(errorNum); importRecord.setNum(indicatorValues.size()); importRecord.setSuccessNum(indicatorValues.size() - errorNum); String key = PublicUtil.getUUID() + user.getUserId(); stringRedisTemplate.opsForValue().set(getEvalImport() + key, JSON.toJSONString(importRecord), 1 , TimeUnit.DAYS); stringRedisTemplate.opsForValue().set(getEvalImportDetail() + key, JSON.toJSONString(details), 1 , TimeUnit.DAYS); EvalIndicatorImportRecordVO recordVO = PublicUtil.copy(importRecord, EvalIndicatorImportRecordVO.class); List detailVos = PublicUtil.copyList(details, EvalIndicatorImportDetailVO.class); recordVO.setDetails(detailVos); recordVO.setKey(key); return recordVO; // evalIndicatorImportRecordService.updateById(importRecord); // evalIndicatorImportDetailService.saveBatch(details); // for (String indicatorCode : uploadIndicatorCodes) { // ImportEvalIndicatorEvent importEvalIndicatorEvent = new ImportEvalIndicatorEvent(indicatorCode, // importRecord.getId(), importRecord.getGroupId(), importRecord.getUploadTime()); // EventBusUtil.asyncPost(importEvalIndicatorEvent); // } } public EvalIndicatorImportDetailVO convertStaffVo(Optional valueOptional) { EvalIndicatorImportDetailVO detail = new EvalIndicatorImportDetailVO(); detail.setIndicatorName(valueOptional.map(StaffIndicatorValueVO::getIndicatorName).orElse("")); detail.setUserName(valueOptional.map(StaffIndicatorValueVO::getStaffName).orElse("")); detail.setShopName(valueOptional.map(StaffIndicatorValueVO::getShopName).orElse("")); return detail; } public EvalIndicatorImportDetail convertStaffPo(Optional valueOptional) { EvalIndicatorImportDetail detail = new EvalIndicatorImportDetail(); detail.setIndicatorName(valueOptional.map(StaffIndicatorValueVO::getIndicatorName).orElse("")); detail.setUserName(valueOptional.map(StaffIndicatorValueVO::getStaffName).orElse("")); detail.setShopName(valueOptional.map(StaffIndicatorValueVO::getShopName).orElse("")); return detail; } public EvalIndicatorImportDetail convertShopPo(Optional valueOptional) { EvalIndicatorImportDetail detail = new EvalIndicatorImportDetail(); detail.setIndicatorName(valueOptional.map(ShopIndicatorValueVO::getIndicatorName).orElse("")); detail.setShopName(valueOptional.map(ShopIndicatorValueVO::getShopName).orElse("")); return detail; } public List analysisExcel(MultipartFile file, Class tClass) { List indicatorValues = null; ExcelReader reader = null; try { reader = ExcelUtil.getReader(file.getInputStream()); } catch (IOException e) { e.printStackTrace(); } Map headerAlias = ExcelDataUtil.getTitleMappingField(tClass); reader.setHeaderAlias(headerAlias); indicatorValues = reader.readAll(tClass); return indicatorValues; } public LocalDate transferDate(String dataDateStr) { if (PublicUtil.isEmpty(dataDateStr)) { return LocalDate.now(); } LocalDate dataDate = LocalDate.now(); DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy/MM/dd"); try { dataDate = LocalDate.parse(dataDateStr, formatter1); } catch (Exception e) { log.error("考评数据导入,日期转换失败,{},{}", dataDateStr, e); try { dataDate = LocalDate.parse(dataDateStr, formatter2); }catch (Exception e2) { log.error("考评数据导入,日期转换失败,{},{}", dataDateStr, e2); } } return dataDate; } public EvalIndicatorImportRecord createRecord(LoginAuthBean user, DimensionTypeEnum dimensionType) { EvalIndicatorImportRecord importRecord = new EvalIndicatorImportRecord(); importRecord.setImportUserId(user.getUserId()); importRecord.setImportUserName(user.getUserName()); importRecord.setDimensionType(dimensionType); importRecord.setUploadTime(LocalDate.now()); importRecord.setGroupId(user.getGroupId()); importRecord.setYn(Boolean.TRUE); return importRecord; } public MultiKeyMap getShopUserPoolMap(LoginAuthBean user) { YearMonth month = YearMonth.now().minusMonths(12); List pools = evalUserPoolService.getLastPool(month, user.getGroupId()); MultiKeyMap staffPostMap = new MultiKeyMap(); for (EvalUserPool pool : pools) { if (staffPostMap.containsKey(pool.getShopName(), pool.getUserName())) { continue; } staffPostMap.put(pool.getShopName(), pool.getUserName(), pool); } return staffPostMap; } public Map getShopPoolMap(LoginAuthBean user) { YearMonth month = YearMonth.now().minusMonths(12); List pools = evalShopPoolService.getLastPool(month, user.getGroupId()); Map evalShopPoolMap = pools.stream() .collect(Collectors.toMap(EvalShopPool::getShopName, Function.identity(), (v1, v2) -> v1)); return evalShopPoolMap; } public Map getNameIndicatorMap() { List evalIndicators = evalIndicatorService.list(Wrappers.lambdaQuery() .eq(EvalIndicator::getYn, Boolean.TRUE) .eq(EvalIndicator::getEnable, Boolean.TRUE) ); Map evalIndicatorMap = evalIndicators.stream() .collect(Collectors.toMap(EvalIndicator::getName, Function.identity(), (v1, v2) -> v1)); return evalIndicatorMap; } public static List staffTemplateData() { List templates = new ArrayList<>(); StaffIndicatorValueVO valueVO = new StaffIndicatorValueVO(); valueVO.setStaffName("张三"); valueVO.setShopName("宁夏瑞静B4-17店"); valueVO.setIndicatorName("活动成交任务达成率"); valueVO.setIndicatorValue("0.1"); valueVO.setDataDate(DateTimeFormatter.ofPattern("yyyy-MM-dd").format(LocalDate.now())); templates.add(valueVO); return templates; } public static List shopTemplateData() { List templates = new ArrayList<>(); ShopIndicatorValueVO valueVO = new ShopIndicatorValueVO(); valueVO.setShopName("宁夏瑞静B4-17店"); valueVO.setIndicatorName("活动成交任务达成率"); valueVO.setIndicatorValue("0.1"); valueVO.setDataDate(DateTimeFormatter.ofPattern("yyyy-MM-dd").format(LocalDate.now())); templates.add(valueVO); return templates; } }