提交 a53d3dea authored 作者: 000516's avatar 000516

解决与QA导入导出功能冲突

......@@ -94,6 +94,11 @@
<groupId>com.taobao</groupId>
<artifactId>taobao-sdk-java</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
</dependency>
</dependencies>
<build>
......
package com.sfa.operation.config;
import com.sfa.operation.util.excel.ExcelStyleUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.poi.ss.usermodel.DataValidation;
import java.util.List;
/**
* @Author: DouXinYu
* @Date: 2025-12-08 16:43
* @Description: AP导出列配置
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExportColumnConfig {
// 字段名
private String fieldName;
// 表头名
private String headerName;
// 格式(如:日期 yyyy-mm)
private String format;
// 列样式
private ExcelStyleUtils.ExcelStyle style;
// 合法值列表(null/空则不验证)
private List<String> validationValidOptions;
// 输入提示标题(可选)
private String validationPromptTitle;
// 输入提示内容(可选)
private String validationPromptMsg;
// 错误提示标题(可选)
private String validationErrorTitle;
// 错误提示内容(可选)
private String validationErrorMsg;
// 错误级别(默认阻止非法输入)
private int validationErrorStyle = DataValidation.ErrorStyle.STOP;
// 验证生效起始行(默认第1行,跳过表头)
private int validationStartRow = 1;
private int validationEndRow = 1048575;
// 数字最小值(null则不限制)
private Double validationNumberMin;
// 数字最大值(null则不限制)
private Double validationNumberMax;
// 是否允许小数(默认整数)
private boolean validationNumberAllowDecimal = false;
// 标记:是否启用数字验证
private boolean isNumberValidation = false;
// 标记:是否启用条件样式
private boolean conditionalStyling = false;
public ExportColumnConfig(String fieldName, String headerName, String format, ExcelStyleUtils.ExcelStyle style) {
this.fieldName = fieldName;
this.headerName = headerName;
this.format = format;
this.style = style;
}
}
package com.sfa.operation.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Author: DouXinYu
* @Date: 2025-12-11 15:18
* @Description: OSS配置属性
*/
@Data
@Component
@ConfigurationProperties(prefix = "aliyun")
public class OssConfigProperties{
/**
* 访问密钥ID
*/
private String accessKeyId;
/**
* 访问密钥
*/
private String accessKeySecret;
/**
* OSS配置属性
*/
private Oss oss = new Oss();
/**
* OSS其他配置项
*/
@Data
public static class Oss{
/**
* 地域ID
*/
private String regionId;
/**
* 存储空间名称
*/
private String bucketName;
/**
* 静态网站访问地址
*/
private String webJsLink;
/**
* 角色授权
*/
private String stsRoleArm;
private String sessionName;
/**
* 静态网站访问地址前缀
*/
private static final String END_POINT_PREFIX = "https://";
/**
* 静态网站访问地址后缀
*/
private static final String END_POINT_SUFFIX = ".aliyuncs.com";
/**
* 获取静态网站访问地址
* @return 静态网站访问地址
*/
public String getEndPoint(){
return END_POINT_PREFIX + this.getRegionId() + END_POINT_SUFFIX;
}
}
}
package com.sfa.operation.controller.sales.excel;
import com.sfa.common.core.domain.R;
import com.sfa.common.core.enums.ECode;
import com.sfa.common.security.annotation.SalesPermissionCheck;
import com.sfa.operation.pojo.sales.request.SalesApRequest;
import com.sfa.operation.service.sales.export.IExportExcelService;
import com.sfa.operation.strategy.IExportApExcelStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
/**
* @Author: DouXinYu
* @Date: 2025-12-05 17:31
* @Description: 导出excel控制类
*/
@Slf4j
@RestController
@RequestMapping("/sales/export")
public class ApExportExcelController {
@Autowired
private IExportExcelService exportApExcelService;
/**
* 导出常规陈列的excel表格zh
* @param salesApRequest 查询参数
* @return 导出文件
*/
@GetMapping("/download")
@SalesPermissionCheck(value = SalesPermissionCheck.CheckType.USER)
public R exportApDisplayExcel(SalesApRequest salesApRequest, HttpServletResponse response) {
return exportApExcelService.exportApDisplayExcel(salesApRequest, response);
}
}
package com.sfa.operation.controller.sales.excel;
import com.sfa.common.core.domain.R;
import com.sfa.operation.pojo.sales.request.ImportApExcelRequest;
import com.sfa.operation.service.sales.export.IImportExcelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author: DouXinYu
* @Date: 2025-12-10 15:21
* @Description: AP导入excel(填报)控制类
*/
@RestController
@RequestMapping("/sales/import")
public class ApImportExcelController {
@Autowired
private IImportExcelService importExcelService;
@PostMapping("/upload")
public R importApDisplayExcel(@RequestBody ImportApExcelRequest request) {
return importExcelService.importApExcel(request);
}
@PostMapping("/update")
public R updateApDisplayExcel(@RequestBody ImportApExcelRequest request) {
return importExcelService.updateApEntity(request);
}
}
package com.sfa.operation.domain.sales.dao;
import com.sfa.common.core.web.domain.PageInfo;
import com.sfa.operation.domain.sales.entity.SalesApDisplay;
import com.sfa.operation.domain.sales.wq.SalesApWq;
import com.sfa.operation.pojo.sales.excel.SalesApDisplayImportExcelDto;
import com.sfa.operation.pojo.sales.response.SalesApDisplayDto;
import org.springframework.data.repository.query.Param;
import java.util.List;
/**
* @author : liqiulin
......@@ -19,4 +24,9 @@ public interface ISalesApDisplayDao {
Object queryDeptAPReport(SalesApWq build);
Object queryDistAPReport(SalesApWq build);
List<SalesApDisplay> queryDataListByCondition(SalesApWq build);
List<SalesApDisplay> queryByCondition(List<SalesApDisplayImportExcelDto> validDtoList);
boolean batchUpdate( List<SalesApDisplay> updateEntityList);
}
......@@ -2,6 +2,7 @@ package com.sfa.operation.domain.sales.dao.impl;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sfa.common.core.enums.ECode;
import com.sfa.common.core.exception.CheckedException;
......@@ -13,13 +14,17 @@ import com.sfa.operation.domain.sales.dao.ISalesApDisplayDao;
import com.sfa.operation.domain.sales.entity.SalesApDisplay;
import com.sfa.operation.domain.sales.mapper.SalesApDisplayMapper;
import com.sfa.operation.domain.sales.wq.SalesApWq;
import com.sfa.operation.pojo.sales.excel.SalesApDisplayImportExcelDto;
import com.sfa.operation.pojo.sales.response.SalesApDisplayDto;
import com.sfa.operation.util.excel.EntityUpdateCheckUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.util.function.Consumer;
/**
* @author : liqiulin
......@@ -28,7 +33,7 @@ import java.util.*;
*/
@DS("bi")
@Service
public class SalesApDisplayDaoImpl implements ISalesApDisplayDao {
public class SalesApDisplayDaoImpl implements ISalesApDisplayDao {
@Autowired
private SalesApDisplayMapper salesapdisMapper;
......@@ -79,6 +84,57 @@ public class SalesApDisplayDaoImpl implements ISalesApDisplayDao {
return r;
}
@Override
public List<SalesApDisplay> queryDataListByCondition(SalesApWq build) {
LambdaQueryWrapper<SalesApDisplay> queryWrapper = buildWq(build);
List<SalesApDisplay> apDisplayList = salesapdisMapper.selectList(queryWrapper);
return apDisplayList;
}
@Override
public List<SalesApDisplay> queryByCondition(List<SalesApDisplayImportExcelDto> validDtoList) {
// 构建精准匹配的QueryWrapper(每个DTO对应一组AND条件,组间OR连接)
QueryWrapper<SalesApDisplay> wrapper = new QueryWrapper<>();
// 标记是否是第一个OR条件(避免多余的前置OR)
boolean isFirstCondition = true;
for (SalesApDisplayImportExcelDto dto : validDtoList) {
// 字段为空时不参与条件匹配(或根据业务要求改为IS NULL)
Long sadId = dto.getSadId();
String regionName = StringUtils.trimToNull(dto.getRegionName());
String dealerName = StringUtils.trimToNull(dto.getDealerName());
String lineName = StringUtils.trimToNull(dto.getLineName());
// 构建单DTO的AND组合条件
Consumer<QueryWrapper<SalesApDisplay>> singleDtoCondition = w -> {
w.eq(sadId != null, "sad_id", sadId)
.eq(regionName != null, "region_name", regionName)
.eq(dealerName != null, "dealer_name", dealerName)
.eq(lineName != null, "line_name", lineName);
};
// 多条件OR拼接(第一个条件不加OR,避免SQL语法错误)
if (isFirstCondition) {
singleDtoCondition.accept(wrapper);
isFirstCondition = false;
} else {
wrapper.or(singleDtoCondition);
}
}
return salesapdisMapper.selectList(wrapper);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean batchUpdate(List<SalesApDisplay> updateEntityList) {
int affectRows = 0;
List<List<SalesApDisplay>> batchList = EntityUpdateCheckUtil.splitList(updateEntityList, 1000);
for (List<SalesApDisplay> batch : batchList) {
// 批量更新
affectRows = salesapdisMapper.batchUpdate(batch);
}
return affectRows > 0;
}
private LambdaQueryWrapper<SalesApDisplay> buildWq(SalesApWq salesApWq) {
LambdaQueryWrapper<SalesApDisplay> qw = new LambdaQueryWrapper<>();
if (StringUtils.isNotBlank(salesApWq.getDealerCode())) {
......
......@@ -3,6 +3,7 @@ package com.sfa.operation.domain.sales.mapper;
import com.sfa.operation.domain.sales.entity.SalesApDisplay;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.sfa.operation.domain.sales.wq.SalesApWq;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
......@@ -28,6 +29,7 @@ public interface SalesApDisplayMapper extends BaseMapper<SalesApDisplay> {
List<Map<String,Object>> queryDistAPHZReport(SalesApWq build);
List<Map<String, Object>> queryDeptAPHZReportDQ(SalesApWq build);
int batchUpdate(@Param("list") List<SalesApDisplay> validEntities);
}
......
package com.sfa.operation.enums;
import lombok.Getter;
/**
* @Author: DouXinYu
* @Date: 2025-12-05 18:31
* @Description: ap导出页面类型枚举类(与策略对应)
*/
@Getter
public enum ExportAPType {
/**
* 常规陈列策略
*/
NORMAL_DISPLAY_EXPORT("normalDisplayExportStrategy"),
/**
* 档期计划策略
*/
PROMOTION_PLAN_EXPORT("promotionPlanExportStrategy"),
/**
* 零食陈列策略
*/
SNACK_DISPLAY_EXPORT("snackDisplayExportStrategy"),
/**
* 三米两秒策略
*/
THREE_METER_TWO_SECONDS_EXPORT("threeMeterTwoSecondsExportStrategy"),
/**
* 六小金刚策略
*/
SIX_KINGkONG_EXPORT("sixKingKongExportStrategy");
private final String strategy;
ExportAPType(String strategy) {
this.strategy = strategy;
}
}
package com.sfa.operation.enums;
import lombok.Getter;
/**
* @Author: DouXinYu
* @Date: 2025-12-10 16:15
* @Description: 店内执行填报 导入 类型枚举
*/
@Getter
public enum ImportApType {
/**
* 常规陈列导入策略
*/
NORMAL_DISPLAY_IMPORT("normalDisplayImportStrategy"),
/**
* 档期计划导入策略
*/
PROMOTION_PLAN_IMPORT("promotionPlanImportStrategy"),
/**
* 零食陈列导入策略
*/
SNACK_DISPLAY_IMPORT("snackDisplayImportStrategy"),
/**
* 三米两秒导入策略
*/
THREE_METER_TWO_SECONDS_IMPORT("threeMeterSecondsImportStrategy"),
/**
* 六小金刚导入策略
*/
SIX_KINGkONG_IMPORT("sixKingKongImportStrategy");
private final String importStrategy;
ImportApType(String importStrategy) {
this.importStrategy = importStrategy;
}
}
package com.sfa.operation.factory;
import com.sfa.operation.enums.ExportAPType;
import com.sfa.operation.strategy.IExportApExcelStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: DouXinYu
* @Date: 2025-12-08 16:49
* @Description: AP导出excel策略工厂类
*/
@Slf4j
@Component
public class ApExportExcelStrategyFactory {
private final Map<String, IExportApExcelStrategy> exportApExcelStrategyMap;
//构造器注入
@Autowired
public ApExportExcelStrategyFactory(Map<String, IExportApExcelStrategy> exportApExcelStrategyMap) {
this.exportApExcelStrategyMap = exportApExcelStrategyMap;
}
public IExportApExcelStrategy getStrategy(String exportApType) {
if (exportApType == null || exportApType.trim().isEmpty()) {
log.error("AP导出Excel策略工厂:传入的导出类型为空!");
throw new IllegalArgumentException("传入的导出类型为空!");
}
ExportAPType typeEnum;
try {
typeEnum = ExportAPType.valueOf(exportApType.toUpperCase());
} catch (IllegalArgumentException e) {
log.error("AP导出Excel策略工厂:传入的导出类型不存在!目标类型为:{}", exportApType);
throw new IllegalArgumentException("传入的导出类型不存在!");
}
// 从枚举中获取策略Bean名称,再从Map中查找策略
String strategyBeanName = typeEnum.getStrategy();
IExportApExcelStrategy strategy = exportApExcelStrategyMap.get(strategyBeanName);
if (strategy == null) {
log.error("AP导出Excel策略工厂:未找到对应的导出策略!目标策略Bean名称为:{}", strategyBeanName);
throw new IllegalArgumentException("未找到对应的导出策略!");
}
log.info("AP导出Excel策略工厂:找到对应的导出策略!目标策略Bean名称为:{}", strategyBeanName);
return strategy;
}
}
package com.sfa.operation.factory;
import com.sfa.operation.enums.ImportApType;
import com.sfa.operation.strategy.IImportApExcelStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @Author: DouXinYu
* @Date: 2025-12-10 16:23
* @Description: 店内执行上报 - 填报- 导入策略工厂类
*/
@Slf4j
@Component
public class ApImportExcelStrategyFactory {
private final Map<String, IImportApExcelStrategy> importApExcelStrategyMap;
//构造器注入
@Autowired
public ApImportExcelStrategyFactory(Map<String, IImportApExcelStrategy> importApExcelStrategyMap) {
this.importApExcelStrategyMap = importApExcelStrategyMap;
}
/**
* 获取策略
* @param importApType 点击导入的类型
* @return 对应策略实现类
*/
public IImportApExcelStrategy getStrategy(String importApType) {
log.info("店内执行填报导入策略注入开始,目标类型为:{}", importApType);
// 参数校验
if (importApType == null || importApType.trim().isEmpty()){
log.error("店内执行填报导入策略注入失败,失败原因:传入的导入类型为空!");
return null;
}
//转换为枚举类型
ImportApType targetType;
try {
targetType = ImportApType.valueOf(importApType);
} catch (IllegalArgumentException e) {
log.error("店内执行填报导入策略注入失败,失败原因:传入的导入类型不存在!目标类型为:{}", importApType);
return null;
}
// 从枚举中获取策略Bean名称,再从Map中查找策略
String beanName = targetType.getImportStrategy();
IImportApExcelStrategy strategy = importApExcelStrategyMap.get(beanName);
if (strategy == null) {
log.error("店内执行填报导入策略注入失败,失败原因:未找到对应的导入策略!目标策略Bean名称为:{}", beanName);
return null;
}
log.info("店内执行填报导入策略注入成功,目标策略Bean名称为:{}", beanName);
return strategy;
}
}
package com.sfa.operation.pojo.sales.excel;
import lombok.Data;
/**
* @Author: DouXinYu
* @Date: 2025-12-10 16:05
* @Description: 店内执行上报 - 填报 - 常规陈列 导入excel数据传输对象
*/
@Data
public class SalesApDisplayImportExcelDto {
/**
* 主键ID
* 类型:Long
*/
private Long sadId;
/**
* 计划月份
* 注意:Excel中是"YYYY-MM"字符串,导入时需转换为Date类型
*/
private String salesMonth;
/**
* 销售大区
* 类型:String
*/
private String regionName;
/**
* 销售战区
* 类型:String
*/
private String districtName;
/**
* 经销商代码
* 类型:String
*/
private String dealerCode;
/**
* 经销商名称
* 类型:String
*/
private String dealerName;
/**
* 门店编码
* 类型:String
*/
private String storeCode;
/**
* 门店名称
* 类型:String
*/
private String storeName;
/**
* 系统名称
* 类型:String
*/
private String lineName;
/**
* 计划主货架-形式
* 类型:String
*/
private String plannedMainShelfType;
/**
* 实际主货架-形式
* 类型:String
*/
private String actualMainShelfType;
/**
* 计划主货架-数量
* 类型:Integer
*/
private Integer plannedMainShelfQty;
/**
* 实际主货架-数量
* 类型:Integer
*/
private Integer actualMainShelfQty;
/**
* 计划端架-数量
* 类型:Double
*/
private Double plannedEndCapQty;
/**
* 实际端架-数量
* 类型:Double
*/
private Double actualEndCapQty;
/**
* 计划地堆-平米数(㎡)
* 类型:Double
*/
private Double plannedFloorStackArea;
/**
* 实际地堆-平米数(㎡)
* 类型:Double
*/
private Double actualFloorStackArea;
/**
* 计划地堆-数量
* 类型:Integer
*/
private Integer plannedFloorStackQty;
/**
* 实际地堆-数量
* 类型:Integer
*/
private Integer actualFloorStackQty;
/**
* 计划多点陈列-数量+形式
* 类型:String
*/
private String plannedMultiDisplay;
/**
* 实际多点陈列-数量+形式
* 类型:String
*/
private String actualMultiDisplay;
/**
* 计划挂条-数量+形式
* 类型:String
*/
private String plannedHangingStripQuantityForm;
/**
* 实际挂条-数量+形式
* 类型:String
*/
private String actualHangingStripQuantityForm;
/**
* 错误信息
* 类型:String
*/
private String errorMsg;
/**
* 行号
* 类型:Integer
*/
private Integer rowNum;
/**
* 备注
* 类型:String
*/
private String remark;
}
package com.sfa.operation.pojo.sales.request;
import lombok.Data;
/**
* @Author: DouXinYu
* @Date: 2025-12-11 16:12
* @Description: 店内执行上报 - 导入Excel请求参数
*/
@Data
public class ImportApExcelRequest {
private String importApType;
private String importApFilePath;
private String uuid;
}
......@@ -62,6 +62,16 @@ public class SalesApRequest {
*/
private String rqStatus;
/**
* 当前查询的页面类型
* 1.常规陈列 :NORMAL_DISPLAY_EXPORT
* 2.档期计划 :PROMOTION_PLAN_EXPORT
* 3.零食陈列 :SNACK_DISPLAY_EXPORT
* 4.三米两秒 :THREE_METER_TWO_SECONDS_EXPORT
* 5.六小金刚 :SIX_KINGkONG_EXPORT
*/
private String pageType;
// ######################## 通用查询 ########################
/**
......
package com.sfa.operation.pojo.sales.vo;
import lombok.Data;
/**
* @Author: DouXinYu
* @Date: 2025-12-10 15:31
* @Description: 店内执行-填报要更新到表的字段
*/
@Data
public class SalesApDisplayVo {
/**
* 主键ID
*/
private Long sadId;
/**
* 主货架形式(实际)
*/
private String actualMainShelfType;
/**
* 主货架数量(实际)
*/
private Integer actualMainShelfQty;
/**
* 实际-主货架是否执行
* 执行主货架形式 >= 计划主货架形式 && 执行主货架数量 >= 计划主货架数量"
* 执行/未执行
*/
private String actualMainShelfExecuted;
/**
* 端架数量(实际)
*/
private Integer actualEndCapQty;
/**
* 实际-架是否执行
* 执行端架数量 >= 计划端架数量
*/
private String actualEndCapExecuted;
/**
* 地堆平米数(实际)
*/
private Double actualFloorStackArea;
/**
* 地堆数量(实际)
*/
private Integer actualFloorStackQty;
/**
* 实际-地堆是否执行
* 执行平米数 >= 计划平米数 && 执行数量 >= 计划数量"
*/
private String actualFloorStackExecuted;
/**
* 多点陈列数量+形式(实际)
*/
private String actualMultiDisplay;
/**
* 实际-多点陈列是否执行
*
* actualMultiDisplay的值如下时:
* 执行与计划一致:执行
* 执行与计划不一致:未执行
*/
private String actualMultiDisplayExecuted;
/**
* 挂条数量+形式(实际)
*/
private String actualHangingStripQuantityForm;
/**
* 实际-挂条是否执行
*
* actualHangingStripQuantityForm的值如下时:
* 执行与计划一致:执行
* 执行与计划不一致:未执行
*/
private String hangingStripExecuted;
/**
* 备注信息
*
*/
private String remark ;
}
package com.sfa.operation.service.sales;
import com.sfa.operation.domain.sales.entity.SalesApDisplay;
import com.sfa.operation.pojo.sales.request.SalesApRequest;
import java.util.List;
/**
* @author : liqiulin
* @date : 2025-09-16 16
......@@ -19,4 +22,6 @@ public interface IApDisplayCoreService {
void putDisplayJDetail(SalesApRequest request);
void putPromotionDetail(SalesApRequest request);
boolean batchUpdate(List<SalesApDisplay> updateEntityList);
}
package com.sfa.operation.service.sales;
import com.sfa.common.core.web.domain.PageInfo;
import com.sfa.operation.domain.sales.entity.SalesApDisplay;
import com.sfa.operation.pojo.sales.excel.SalesApDisplayImportExcelDto;
import com.sfa.operation.pojo.sales.request.SalesApRequest;
import java.util.List;
......@@ -28,4 +30,6 @@ public interface IApDisplayQueryService {
Object queryDeptAPReport(SalesApRequest request);
Object queryDistAPReport(SalesApRequest request);
List<SalesApDisplay> queryDataListByCondition(SalesApRequest build);
List<SalesApDisplay> queryByCondition(List<SalesApDisplayImportExcelDto> queryParam);
}
package com.sfa.operation.service.sales.export;
import com.sfa.common.core.domain.R;
import com.sfa.operation.pojo.sales.request.SalesApRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Author: DouXinYu
* @Date: 2025-12-09 14:20
* @Description:
*/
public interface IExportExcelService {
R exportApDisplayExcel(SalesApRequest salesApRequest, HttpServletResponse response);
}
package com.sfa.operation.service.sales.export;
import com.sfa.common.core.domain.R;
import com.sfa.operation.pojo.sales.request.ImportApExcelRequest;
/**
* @Author: DouXinYu
* @Date: 2025-12-12 13:11
* @Description: 导入excel服务接口
*/
public interface IImportExcelService {
R importApExcel(ImportApExcelRequest request);
R updateApEntity(ImportApExcelRequest request);
}
package com.sfa.operation.service.sales.export.impl;
import com.sfa.common.core.domain.R;
import com.sfa.operation.factory.ApExportExcelStrategyFactory;
import com.sfa.operation.pojo.sales.request.SalesApRequest;
import com.sfa.operation.service.sales.export.IExportExcelService;
import com.sfa.operation.strategy.IExportApExcelStrategy;
import com.sfa.operation.util.excel.ExcelUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
/**
* @Author: DouXinYu
* @Date: 2025-12-09 14:20
* @Description: 导出excel服务实现类
*/
@Slf4j
@Service
public class ExportExcelServiceImpl implements IExportExcelService {
@Autowired
private ApExportExcelStrategyFactory exportApExcelStrategyFactory;
@Override
public R exportApDisplayExcel(SalesApRequest salesApRequest, HttpServletResponse response) {
try {
IExportApExcelStrategy strategy = exportApExcelStrategyFactory.getStrategy(salesApRequest.getPageType());
String fileNamePrefix = strategy.getExportFileNamePrefix();
log.info("导出前缀为:{}的excel", fileNamePrefix);
byte[] excelBytesArray = strategy.generateExcel(salesApRequest);
ExcelUtils.exportExcelBytesToResponse(excelBytesArray, response, fileNamePrefix);
log.info("常规陈列数据导出成功!");
return R.ok(R.SUCCESS, "数据导出成功") ;
} catch (Exception e) {
log.error("常规陈列数据导出异常!具体错误原因:", e);
return R.fail(R.FAIL,"数据导出失败,请联系后台管理员处理!");
}
}
}
package com.sfa.operation.service.sales.export.impl;
import com.alibaba.fastjson2.JSONObject;
import com.sfa.common.core.domain.R;
import com.sfa.operation.factory.ApImportExcelStrategyFactory;
import com.sfa.operation.pojo.sales.request.ImportApExcelRequest;
import com.sfa.operation.service.sales.export.IImportExcelService;
import com.sfa.operation.strategy.IImportApExcelStrategy;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @Author: DouXinYu
* @Date: 2025-12-12 13:11
* @Description: 导入excel服务实现类
*/
@Slf4j
@Service
public class ImportExcelServiceImpl implements IImportExcelService {
@Autowired
private ApImportExcelStrategyFactory apImportExcelStrategyFactory;
@Autowired
private StringRedisTemplate stringRedisTemplate;
public static final String REDIS_KEY_PREFIX = "import_excel_ap:";
/**
* 店内执行上上报 -导入方法
*
* @param request 导入excel请求参数
* @return 导入结果
*/
@Override
public R importApExcel(ImportApExcelRequest request) {
// 参数校验
if (request == null || request.getImportApFilePath() == null || request.getImportApFilePath().trim().isEmpty()){
return R.fail("导入文件路径不能为空!");
}
if (request.getImportApType() == null || request.getImportApType().trim().isEmpty()){
return R.fail("导入类型不能为空!");
}
// 获取策略
IImportApExcelStrategy strategy = apImportExcelStrategyFactory.getStrategy(request.getImportApType());
if (strategy == null){
return R.fail("未找到对应的导入策略!");
}
// 执行导入的数据验证(根据不同的策略独自设计验证)
Map<String, Object> result = strategy.execute(request.getImportApFilePath());
Integer failCount = (Integer) result.get("failCount");
//failCount>0 时 返回错误信息
if (failCount>0 ) {
log.error("导入失败,失败条数:{}",failCount);
return R.fail(result);
} else {
String uuid = (String) result.getOrDefault("uuid", "");
String redisKey = REDIS_KEY_PREFIX + uuid;
//将数据保存躁redis中
stringRedisTemplate.opsForValue().set(redisKey, JSONObject.toJSONString(result), 30, TimeUnit.MINUTES);
log.info("数据保存至redis中,redisKey={},result={}", redisKey, JSONObject.toJSONString(result));
}
return R.ok(result);
}
/**
* 前端点击确认后 更新数据
* @param request 导入excel请求参数
* @return 导入结果
*/
@Override
public R updateApEntity(ImportApExcelRequest request) {
if (request.getImportApType() == null || request.getImportApType().trim().isEmpty()){
return R.fail("导入类型不能为空!");
}
if (request.getUuid() == null || request.getUuid().trim().isEmpty()){
return R.fail("导入数据标识不能为空!");
}
// 获取策略
IImportApExcelStrategy strategy = apImportExcelStrategyFactory.getStrategy(request.getImportApType());
if (strategy == null){
return R.fail("未找到对应的导入策略!");
}
//从redis获取数据
String redisKey = REDIS_KEY_PREFIX+ request.getUuid();
String redisValue = stringRedisTemplate.opsForValue().get(redisKey);
//解析jsonToDtoList
List list = strategy.getTransactionJsonToObject(redisValue);
//批量更新
String result = strategy.updateDisplay(list);
if ("更新失败".equals(result)) {
return R.fail(result);
}
return R.ok(result);
}
}
......@@ -3,6 +3,7 @@ package com.sfa.operation.service.sales.impl;
import cn.hutool.core.date.DatePattern;
import com.sfa.common.security.utils.SecurityUtils;
import com.sfa.operation.domain.sales.dao.*;
import com.sfa.operation.domain.sales.entity.SalesApDisplay;
import com.sfa.operation.pojo.sales.request.SalesApRequest;
import com.sfa.operation.pojo.sales.response.*;
import com.sfa.operation.service.sales.IApDisplayCoreService;
......@@ -12,6 +13,7 @@ import org.springframework.stereotype.Service;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
......@@ -78,6 +80,16 @@ public class ApDisplayCoreServiceImpl implements IApDisplayCoreService {
salesApDisplayJDao.updateDetail(djDto);
}
/**
*
* @param updateEntityList
* @return
*/
@Override
public boolean batchUpdate(List<SalesApDisplay> updateEntityList) {
return salesApDisplayDao.batchUpdate(updateEntityList);
}
@Override
public void putPromotionDetail(SalesApRequest request) {
// 修改DB 日期值为null
......@@ -110,4 +122,6 @@ public class ApDisplayCoreServiceImpl implements IApDisplayCoreService {
e.printStackTrace();
}
}
}
......@@ -5,11 +5,14 @@ import cn.hutool.core.date.DateUtil;
import com.sfa.common.core.utils.bean.BeanUtils;
import com.sfa.common.core.web.domain.PageInfo;
import com.sfa.operation.domain.sales.dao.*;
import com.sfa.operation.domain.sales.entity.SalesApDisplay;
import com.sfa.operation.domain.sales.wq.SalesApWq;
import com.sfa.operation.pojo.sales.excel.SalesApDisplayImportExcelDto;
import com.sfa.operation.pojo.sales.request.SalesApRequest;
import com.sfa.operation.service.sales.IApDisplayQueryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author : liqiulin
......@@ -76,10 +79,21 @@ public class ApDisplayQueryServiceImpl implements IApDisplayQueryService {
return salesApDisplayDao.queryDistAPReport(build(request));
}
@Override
public List<SalesApDisplay> queryDataListByCondition(SalesApRequest request) {
return salesApDisplayDao.queryDataListByCondition(build(request));
}
@Override
public List<SalesApDisplay> queryByCondition(List<SalesApDisplayImportExcelDto> validDtoList) {
return salesApDisplayDao.queryByCondition(validDtoList);
}
private SalesApWq build(SalesApRequest salesApRequest){
SalesApWq salesApWq = new SalesApWq();
BeanUtils.copyProperties(salesApRequest,salesApWq);
salesApWq.setSalesMonth(salesApRequest.getSalesMonth() != null ? DateUtil.parse(salesApRequest.getSalesMonth() + "-01", DatePattern.NORM_DATE_PATTERN) : null);
return salesApWq;
}
}
package com.sfa.operation.strategy;
import com.sfa.operation.config.ExportColumnConfig;
import com.sfa.operation.pojo.sales.request.SalesApRequest;
import com.sfa.operation.util.excel.ExcelUtils;
import java.util.List;
/**
* @Author: DouXinYu
* @Date: 2025-12-08 16:17
* @Description: 策略接口
*/
public interface IExportApExcelStrategy {
/**
* 获取导出列配置
*
* @return 导出列配置
*/
List<ExportColumnConfig> getExportColumnConfig();
/**
* 查询数据
*
* @param salesApRequest 请求参数
* @return 查询结果
*/
List<?> queryData(SalesApRequest salesApRequest);
/**
* 获取导出sheet名称
*/
String getExportSheetName();
/**
* 获取导出文件名前缀
*
* @return 导出文件名前缀
*/
String getExportFileNamePrefix();
/**
* 生成excel
*
* @param salesApRequest 请求参数
* @return excel字节数组
*/
default byte[] generateExcel(SalesApRequest salesApRequest) throws Exception {
return ExcelUtils.generateExcelBytes(
this.getExportColumnConfig(),
this.queryData(salesApRequest),
this.getExportSheetName()
);
}
}
package com.sfa.operation.strategy;
import com.sfa.operation.config.ExportColumnConfig;
import com.sfa.operation.domain.sales.entity.SalesApDisplay;
import com.sfa.operation.pojo.sales.excel.SalesApDisplayImportExcelDto;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
/**
* @Author: DouXinYu
* @Date: 2025-12-10 16:21
* @Description: 店内执行填报 - 导入策略接口
*/
public interface IImportApExcelStrategy<T> {
/**
* 获取导入列配置(复用导出列配置)
*/
List<ExportColumnConfig> getImportColumnConfig();
/**
* 解析Excel文件流为DTO列表
*/
List<T> parseExcelToDtoList(InputStream inputStream, String flePathUrl,Map<String, List<T>> errorMap);
/**
* 预处理DTO数据(补充关联数据)
*/
void preprocessData(List<T> dtoList);
/**
* 数据库批量操作(新增/更新)
*/
int queryAndBatchOperate(List<T> dtoList);
/**
* 构建更新实体列表
*/
List<?>buildUpdateEntityList(List<T> dtoList);
/**
* 查询数据库数据
*/
List<?> queryData(List<T> dto);
/**
* 更新数据库数据
*/
String updateDisplay(List<T> dtoList);
List<T> getTransactionJsonToObject(String json);
/**
* 导入核心执行方法
*/
Map<String, Object> execute(String flePathUrl);
/**
* 获取导入Sheet名称(默认方法)
*/
default String getImportSheetName() {
return "";
}
}
package com.sfa.operation.strategy.impl.exports;
import com.sfa.operation.config.ExportColumnConfig;
import com.sfa.operation.pojo.sales.request.SalesApRequest;
import com.sfa.operation.service.sales.IApDisplayQueryService;
import com.sfa.operation.strategy.IExportApExcelStrategy;
import com.sfa.operation.util.excel.ExcelStyleUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @Author: DouXinYu
* @Date: 2025-12-08 17:24
* @Description: 常规陈列策略接口实现类
*/
@Component("normalDisplayExportStrategy")
public class NormalDisplayExportStrategyImpl implements IExportApExcelStrategy {
private static final String EXPORT_SHEET_NAME = "常规陈列";
private static final String EXPORT_FILE_NAME_PREFIX = "常规陈列";
@Autowired
private IApDisplayQueryService apDisplayQueryService;
/**
* 获取导出列配置
* @return 列配置
*/
@Override
public List<ExportColumnConfig> getExportColumnConfig() {
List<ExportColumnConfig> column = new ArrayList<>();
//处理填报列的规则限制
//主货架形式-实际
ExportColumnConfig actualMainShelfType = new ExportColumnConfig("actualMainShelfType", "主货架形式(实际)", "", ExcelStyleUtils.ExcelStyle.LIGHT_BLUE_BG);
actualMainShelfType.setValidationValidOptions(Arrays.asList("3纵", "4纵", "5纵", "6纵", "7纵", "8纵及以上"));
actualMainShelfType.setValidationErrorTitle("输入错误");
actualMainShelfType.setValidationErrorMsg("主货架形式必须输入”3纵、4纵、5纵、6纵、7纵、8纵及以上“之一!");
actualMainShelfType.setConditionalStyling(true);
//主货架数量-实际
ExportColumnConfig actualMainShelfQty = new ExportColumnConfig("actualMainShelfQty", "主货架数量(实际)", "", ExcelStyleUtils.ExcelStyle.LIGHT_BLUE_BG);
actualMainShelfQty.setNumberValidation(true);
actualMainShelfQty.setValidationNumberMin(0.0);
actualMainShelfQty.setValidationNumberMax(999999999999999999.999999999999999999);
actualMainShelfQty.setValidationErrorTitle("输入错误");
actualMainShelfQty.setValidationErrorMsg("主货架数量必须输入大于等于0的数字!");
actualMainShelfQty.setConditionalStyling(true);
//端架数量-实际
ExportColumnConfig actualEndCapQty = new ExportColumnConfig("actualEndCapQty", "端架数量(实际)", "", ExcelStyleUtils.ExcelStyle.LIGHT_BLUE_BG);
actualEndCapQty.setNumberValidation(true);
actualEndCapQty.setValidationNumberMin(0.0);
actualEndCapQty.setValidationNumberMax(999999999999999999.999999999999999999);
actualEndCapQty.setValidationErrorTitle("输入错误");
actualEndCapQty.setValidationErrorMsg("端架数量必须输入大于等于0的数字!");
actualEndCapQty.setConditionalStyling(true);
//地堆面积-实际
ExportColumnConfig actualFloorStackArea = new ExportColumnConfig("actualFloorStackArea", "地堆平米数(实际)", "", ExcelStyleUtils.ExcelStyle.LIGHT_GREY_BG);
actualFloorStackArea.setValidationValidOptions(Arrays.asList("0","0.5","0.8","1","2","3","4","5","6","8"));
actualFloorStackArea.setValidationErrorTitle("输入错误");
actualFloorStackArea.setValidationErrorMsg("地堆面积必须输入0、0.5、0.8、1、2、3、4、5、6、8之一!");
actualFloorStackArea.setConditionalStyling(true);
//地堆数量-实际
ExportColumnConfig actualFloorStackQty = new ExportColumnConfig("actualFloorStackQty", "地堆数量(实际)", "", ExcelStyleUtils.ExcelStyle.LIGHT_GREY_BG);
actualFloorStackQty.setValidationValidOptions(Arrays.asList("0","1","2","3","4","5"));
actualFloorStackQty.setValidationErrorTitle("输入错误");
actualFloorStackQty.setValidationErrorMsg("地堆数量必须输入0、1、2、3、4、5之一!");
actualFloorStackQty.setConditionalStyling(true);
//多点陈列数量形式-实际
ExportColumnConfig actualMultiDisplay = new ExportColumnConfig("actualMultiDisplay", "多点陈列数量形式(实际)", "", ExcelStyleUtils.ExcelStyle.LIGHT_BLUE_BG);
actualMultiDisplay.setValidationValidOptions(Arrays.asList("执行与计划一致", "执行与计划不一致"));
actualMultiDisplay.setValidationErrorTitle("输入错误");
actualMultiDisplay.setValidationErrorMsg("多点陈列数量形式必须输入“执行与计划一致”或“执行与计划不一致”!");
actualMultiDisplay.setConditionalStyling(true);
//挂条数量形式-实际
ExportColumnConfig actualHangingStripQuantityForm = new ExportColumnConfig("actualHangingStripQuantityForm", "挂条数量形式(实际)", "", ExcelStyleUtils.ExcelStyle.LIGHT_BLUE_BG);
actualHangingStripQuantityForm.setValidationValidOptions(Arrays.asList("执行与计划一致", "执行与计划不一致"));
actualHangingStripQuantityForm.setValidationErrorTitle("输入错误");
actualHangingStripQuantityForm.setValidationErrorMsg("挂条数量形式必须输入“执行与计划一致”或“执行与计划不一致”!");
actualHangingStripQuantityForm.setConditionalStyling(true);
column.add(new ExportColumnConfig("sadId", "程序编号-请忽略", "", ExcelStyleUtils.ExcelStyle.UNMODIFIABLE));
column.add(new ExportColumnConfig("salesMonth", "计划月份", "YYYY-MM", ExcelStyleUtils.ExcelStyle.UNMODIFIABLE));
column.add(new ExportColumnConfig("regionName", "销售大区", "", ExcelStyleUtils.ExcelStyle.UNMODIFIABLE));
column.add(new ExportColumnConfig("districtName", "销售战区", "", ExcelStyleUtils.ExcelStyle.UNMODIFIABLE));
column.add(new ExportColumnConfig("dealerCode", "经销商代码", "@", ExcelStyleUtils.ExcelStyle.CHANGE_TEXT_STYLE));
column.add(new ExportColumnConfig("dealerName", "经销商名称", "", ExcelStyleUtils.ExcelStyle.UNMODIFIABLE));
column.add(new ExportColumnConfig("storeCode", "门店编码", "", ExcelStyleUtils.ExcelStyle.UNMODIFIABLE));
column.add(new ExportColumnConfig("storeName", "门店名称", "", ExcelStyleUtils.ExcelStyle.UNMODIFIABLE));
column.add(new ExportColumnConfig("lineName", "系统名称", "", ExcelStyleUtils.ExcelStyle.UNMODIFIABLE));
column.add(new ExportColumnConfig("plannedMainShelfType", "主货架形式(计划)", "", ExcelStyleUtils.ExcelStyle.UNMODIFIABLE));
column.add(actualMainShelfType);
column.add(new ExportColumnConfig("plannedMainShelfQty", "主货架数量(计划)", "", ExcelStyleUtils.ExcelStyle.UNMODIFIABLE));
column.add(actualMainShelfQty);
column.add(new ExportColumnConfig("plannedEndCapQty", "端架数量(计划)", "", ExcelStyleUtils.ExcelStyle.UNMODIFIABLE));
column.add(actualEndCapQty);
column.add(new ExportColumnConfig("plannedFloorStackArea", "地堆平米数(计划)", "", ExcelStyleUtils.ExcelStyle.UNMODIFIABLE));
column.add(actualFloorStackArea);
column.add(new ExportColumnConfig("plannedFloorStackQty", "地堆数量(计划)", "", ExcelStyleUtils.ExcelStyle.UNMODIFIABLE));
column.add(actualFloorStackQty);
column.add(new ExportColumnConfig("plannedMultiDisplay", "多点陈列数量形式(计划)", "", ExcelStyleUtils.ExcelStyle.UNMODIFIABLE));
column.add(actualMultiDisplay);
column.add(new ExportColumnConfig("plannedHangingStripQuantityForm", "挂条数量形式(计划)", "", ExcelStyleUtils.ExcelStyle.UNMODIFIABLE));
column.add(actualHangingStripQuantityForm);
column.add(new ExportColumnConfig("remark", "备注", "", ExcelStyleUtils.ExcelStyle.DEFAULT_STYLE));
for (ExportColumnConfig exportColumnConfig : column) {
System.out.println(exportColumnConfig.toString());
}
return column;
}
/**
* 查询数据
* @param salesApRequest 请求参数
* @return 根据条换查询出的数据列表
*/
@Override
public List<?> queryData(SalesApRequest salesApRequest) {
return apDisplayQueryService.queryDataListByCondition(salesApRequest);
}
@Override
public String getExportSheetName() {
return EXPORT_SHEET_NAME;
}
@Override
public String getExportFileNamePrefix() {
return EXPORT_FILE_NAME_PREFIX;
}
}
package com.sfa.operation.util.excel;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* 实体更新字段校验工具
*/
public class EntityUpdateCheckUtil {
private static final Logger log = LoggerFactory.getLogger(EntityUpdateCheckUtil.class);
/**
* 校验实体是否有「非主键的有效更新字段」
* @param entity 待校验实体
* @return true=有有效字段,false=无有效字段
*/
public static <T> boolean hasValidUpdateField(T entity) {
if (entity == null) {
return false;
}
Class<?> clazz = entity.getClass();
Field[] fields = clazz.getDeclaredFields();
boolean hasUpdateField = false;
for (Field field : fields) {
field.setAccessible(true);
String fieldName = field.getName();
try {
Object fieldValue = field.get(entity);
// 跳过主键字段(带@TableId注解)
if (field.isAnnotationPresent(TableId.class)) {
continue;
}
// 跳过不参与更新的字段(如@TableField(updateStrategy = FieldStrategy.NEVER))
TableField tableField = field.getAnnotation(TableField.class);
if (tableField != null && tableField.updateStrategy().equals(FieldStrategy.NEVER)) {
continue;
}
// 存在非空的更新字段
if (fieldValue != null) {
hasUpdateField = true;
break;
}
} catch (IllegalAccessException e) {
log.error("反射校验实体字段失败:fieldName={}", fieldName, e);
}
}
return hasUpdateField;
}
public static <T> List<List<T>> splitList(List<T> list, int batchSize) {
List<List<T>> batches = new ArrayList<>();
for (int i = 0; i < list.size(); i += batchSize) {
int end = Math.min(i + batchSize, list.size());
batches.add(list.subList(i, end));
}
return batches;
}
}
\ No newline at end of file
......@@ -711,6 +711,7 @@
group by region_name) sp
on ar.region_name = sp.region_name order by ar.region_name
</select>
<select id="queryDeptAPHZReportDQ" parameterType="com.sfa.operation.domain.sales.wq.SalesApWq" resultType="java.util.Map">
SELECT '合计:' as regionName,
d.主货架计划网点数 as planMsStoreCnt,
......@@ -1193,4 +1194,94 @@
</where>
) sp;
</select>
<!-- 批量更新SQL -->
<update id="batchUpdate">
UPDATE sales_ap_display
<trim prefix="SET" suffixOverrides=",">
<!-- 实际主货架类型 -->
actual_main_shelf_type = CASE
<foreach collection="list" item="item" separator="">
WHEN sad_id = #{item.sadId} THEN #{item.actualMainShelfType}
</foreach>
END,
<!-- 实际主货架数量 -->
actual_main_shelf_qty = CASE
<foreach collection="list" item="item" separator="">
WHEN sad_id = #{item.sadId} THEN #{item.actualMainShelfQty}
</foreach>
END,
<!-- 实际主货架执行状态 -->
actual_main_shelf_executed = CASE
<foreach collection="list" item="item" separator="">
WHEN sad_id = #{item.sadId} THEN #{item.actualMainShelfExecuted}
</foreach>
END,
<!-- 实际端架数量 -->
actual_end_cap_qty = CASE
<foreach collection="list" item="item" separator="">
WHEN sad_id = #{item.sadId} THEN #{item.actualEndCapQty}
</foreach>
END,
<!-- 实际端架执行状态 -->
actual_end_cap_executed = CASE
<foreach collection="list" item="item" separator="">
WHEN sad_id = #{item.sadId} THEN #{item.actualEndCapExecuted}
</foreach>
END,
<!-- 实际堆头面积 -->
actual_floor_stack_area = CASE
<foreach collection="list" item="item" separator="">
WHEN sad_id = #{item.sadId} THEN #{item.actualFloorStackArea}
</foreach>
END,
<!-- 实际堆头数量 -->
actual_floor_stack_qty = CASE
<foreach collection="list" item="item" separator="">
WHEN sad_id = #{item.sadId} THEN #{item.actualFloorStackQty}
</foreach>
END,
<!-- 实际堆头执行状态 -->
actual_floor_stack_executed = CASE
<foreach collection="list" item="item" separator="">
WHEN sad_id = #{item.sadId} THEN #{item.actualFloorStackExecuted}
</foreach>
END,
<!-- 实际多点陈列 -->
actual_multi_display = CASE
<foreach collection="list" item="item" separator="">
WHEN sad_id = #{item.sadId} THEN #{item.actualMultiDisplay}
</foreach>
END,
<!-- 实际多点陈列执行状态 -->
actual_multi_display_executed = CASE
<foreach collection="list" item="item" separator="">
WHEN sad_id = #{item.sadId} THEN #{item.actualMultiDisplayExecuted}
</foreach>
END,
<!-- 实际挂条数量 -->
actual_hanging_strip_quantity_form = CASE
<foreach collection="list" item="item" separator="">
WHEN sad_id = #{item.sadId} THEN #{item.actualHangingStripQuantityForm}
</foreach>
END,
<!-- 挂条执行状态 -->
hanging_strip_executed = CASE
<foreach collection="list" item="item" separator="">
WHEN sad_id = #{item.sadId} THEN #{item.hangingStripExecuted}
</foreach>
END,
<!-- 备注 -->
remark = CASE
<foreach collection="list" item="item" separator="">
WHEN sad_id = #{item.sadId} THEN #{item.remark}
</foreach>
END
</trim>
<!-- 只更新传入的主键范围(避免全表更新) -->
WHERE sad_id IN
<foreach collection="list" item="item" open="(" separator="," close=")">
#{item.sadId}
</foreach>
</update>
</mapper>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论