farm模块-溯源

This commit is contained in:
顾君禹
2025-09-05 14:33:26 +08:00
parent 5de9465171
commit b1c101a20f
10 changed files with 874 additions and 44 deletions

View File

@@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.farm.controller.admin.traceabilitycode.vo.Traceab
import cn.iocoder.yudao.module.farm.controller.admin.traceabilitycode.vo.TraceabilityCodeRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.traceabilitycode.vo.TraceabilityCodeSaveReqVO;
import cn.iocoder.yudao.module.farm.dal.dataobject.traceabilitycode.TraceabilityCodeDO;
import cn.iocoder.yudao.module.farm.framework.util.TraceabilityDataConverter;
import cn.iocoder.yudao.module.farm.service.traceabilitycode.TraceabilityCodeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@@ -69,14 +70,20 @@ public class TraceabilityCodeController {
@Parameter(name = "id", description = "编号", required = true, example = "1024")
public CommonResult<TraceabilityCodeRespVO> getTraceabilityCode(@RequestParam("id") String id) {
TraceabilityCodeDO traceabilityCode = traceabilityCodeService.getTraceabilityCode(id);
return success(BeanUtils.toBean(traceabilityCode, TraceabilityCodeRespVO.class));
return success(TraceabilityDataConverter.convertToRespVO(traceabilityCode));
}
@GetMapping("/page")
@Operation(summary = "获得溯源-溯源码分页")
public CommonResult<PageResult<TraceabilityCodeRespVO>> getTraceabilityCodePage(@Valid TraceabilityCodePageReqVO pageReqVO) {
PageResult<TraceabilityCodeDO> pageResult = traceabilityCodeService.getTraceabilityCodePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, TraceabilityCodeRespVO.class));
// 转换分页结果中的每个DO对象为RespVO对象
PageResult<TraceabilityCodeRespVO> respPageResult = new PageResult<>();
respPageResult.setList(pageResult.getList().stream()
.map(TraceabilityDataConverter::convertToRespVO)
.toList());
respPageResult.setTotal(pageResult.getTotal());
return success(respPageResult);
}
@GetMapping("/export-excel")

View File

@@ -35,8 +35,15 @@ public class TraceabilityCodePageReqVO extends PageParam {
private String tenantId;
@Schema(description = "采收时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] harvestDate;
private String harvestDate;
@Schema(description = "采收时间范围查询-开始时间")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private String harvestDateStart;
@Schema(description = "采收时间范围查询-结束时间")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private String harvestDateEnd;
@Schema(description = "农事记录", example = "24734")
private Long farmingInputCount;

View File

@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.farm.controller.admin.traceabilitycode.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import cn.idev.excel.annotation.*;
@@ -46,7 +45,7 @@ public class TraceabilityCodeRespVO {
@Schema(description = "采收时间")
@ExcelProperty("采收时间")
private LocalDateTime harvestDate;
private String harvestDate;
@Schema(description = "农事记录", example = "24734")
@ExcelProperty("农事记录")
@@ -81,7 +80,7 @@ public class TraceabilityCodeRespVO {
@Schema(description = "商品认证")
@ExcelProperty("商品认证")
private String brandAuthentication;
private String brandAuthenticationStr;
@Schema(description = "企业id", example = "25407")
@ExcelProperty("企业id")
@@ -91,9 +90,9 @@ public class TraceabilityCodeRespVO {
@ExcelProperty("企业名称")
private String businessName;
@Schema(description = "是否显示企业名称", example = "张三")
@Schema(description = "是否显示企业名称", example = "true")
@ExcelProperty("是否显示企业名称")
private Long isShowBusinessName;
private Boolean isShowBusinessName;
@Schema(description = "联系电话")
@ExcelProperty("联系电话")
@@ -101,15 +100,15 @@ public class TraceabilityCodeRespVO {
@Schema(description = "是否显示联系电话")
@ExcelProperty("是否显示联系电话")
private Long isShowBusinessPhone;
private Boolean isShowBusinessPhone;
@Schema(description = "企业网店", example = "李四")
@ExcelProperty("企业网店")
private String storeName;
@Schema(description = "是否显示企业网店", example = "张三")
@Schema(description = "是否显示企业网店", example = "true")
@ExcelProperty("是否显示企业网店")
private Long isShowStoreName;
private Boolean isShowStoreName;
@Schema(description = "企业地址")
@ExcelProperty("企业地址")
@@ -117,7 +116,7 @@ public class TraceabilityCodeRespVO {
@Schema(description = "是否显示企业地址")
@ExcelProperty("是否显示企业地址")
private Long isShowBusinessAddress;
private Boolean isShowBusinessAddress;
@Schema(description = "宣传图片(逗号分隔的字符串)")
@ExcelProperty("宣传图片")
@@ -128,7 +127,7 @@ public class TraceabilityCodeRespVO {
@Schema(description = "是否显示宣传图片")
@ExcelProperty("是否显示宣传图片")
private Long isShowPublicityImage;
private Boolean isShowPublicityImage;
@Schema(description = "企业简介")
@ExcelProperty("企业简介")
@@ -136,7 +135,7 @@ public class TraceabilityCodeRespVO {
@Schema(description = "是否显示企业简介")
@ExcelProperty("是否显示企业简介")
private Long isShowPublicityProfile;
private Boolean isShowPublicityProfile;
@Schema(description = "批次检验报告")
@ExcelProperty("批次检验报告")
@@ -170,4 +169,108 @@ public class TraceabilityCodeRespVO {
private LocalDateTime createTime;
private String codeOutBatch;
private Long scanCodeCount;
// ========== 新增字段支持复杂JSON结构 ==========
@Schema(description = "农事记录列表")
private List<FarmingInputItem> farmingInputList;
@Schema(description = "品牌认证列表")
private List<String> brandAuthentication;
@Schema(description = "检验报告列表")
private List<String> inspectionReportList;
@Schema(description = "计量单位", example = "3")
private Integer measuringUnit;
@Schema(description = "包装单位", example = "8")
private Integer packingUnit;
@Schema(description = "自定义数据列表")
private List<CustomDataItem> customData;
@Schema(description = "是否显示基地")
private Boolean isShowBase;
@Schema(description = "农事记录JSON数据")
private String farmingInputJson;
@Schema(description = "自定义数据JSON")
private String customDataJson;
@Schema(description = "农事记录项")
@Data
public static class FarmingInputItem {
@Schema(description = "农事名称", example = "123")
private String farmingName;
@Schema(description = "农事日期列表")
private List<String> date;
@Schema(description = "投入品列表")
private List<InputItem> inputList;
@Schema(description = "农事图片列表")
private List<String> imageList;
}
@Schema(description = "投入品项")
@Data
public static class InputItem {
@Schema(description = "投入品ID", example = "97e9f792-3b84-4132-9350-b08f34641c65")
private String inputsId;
@Schema(description = "资产类型", example = "2")
private Integer assetType;
@Schema(description = "用量", example = "100")
private java.math.BigDecimal dose;
@Schema(description = "单位", example = "6")
private Integer unit;
@Schema(description = "包装单位", example = "1")
private Integer packageUnit;
@Schema(description = "稀释倍液", example = "1.5倍")
private String diluted;
@Schema(description = "用法", example = "123")
private String usage;
@Schema(description = "投入品名称", example = "药物")
private String inputsName;
@Schema(description = "单位名称")
private String unitName;
@Schema(description = "包装单位名称")
private String packageUnitName;
}
@Schema(description = "自定义数据项")
@Data
public static class CustomDataItem {
@Schema(description = "链接名称")
private String linkName;
@Schema(description = "自定义区块列表")
private List<CustomSection> customSection;
@Schema(description = "自定义区块")
@Data
public static class CustomSection {
@Schema(description = "标签")
private String label;
@Schema(description = "类型")
private Integer type;
@Schema(description = "内容")
private String content;
@Schema(description = "图片列表")
private List<String> imageList;
}
}
}

View File

@@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.farm.controller.admin.traceabilitycode.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import jakarta.validation.constraints.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 溯源-溯源码新增/修改 Request VO")
@@ -36,7 +34,7 @@ public class TraceabilityCodeSaveReqVO {
private String tenantId;
@Schema(description = "采收时间")
private LocalDateTime harvestDate;
private String harvestDate;
@Schema(description = "农事记录", example = "24734")
private Long farmingInputCount;
@@ -63,7 +61,7 @@ public class TraceabilityCodeSaveReqVO {
private String introduce;
@Schema(description = "商品认证")
private String brandAuthentication;
private String brandAuthenticationStr;
@Schema(description = "企业id", example = "25407")
private String businessId;
@@ -72,25 +70,25 @@ public class TraceabilityCodeSaveReqVO {
private String businessName;
@Schema(description = "是否显示企业名称", example = "张三")
private Long isShowBusinessName;
private Boolean isShowBusinessName;
@Schema(description = "联系电话")
private String businessPhone;
@Schema(description = "是否显示联系电话")
private Long isShowBusinessPhone;
private Boolean isShowBusinessPhone;
@Schema(description = "企业网店", example = "李四")
private String storeName;
@Schema(description = "是否显示企业网店", example = "张三")
private Long isShowStoreName;
private Boolean isShowStoreName;
@Schema(description = "企业地址")
private String businessAddress;
@Schema(description = "是否显示企业地址")
private Long isShowBusinessAddress;
private Boolean isShowBusinessAddress;
@Schema(description = "宣传图片(逗号分隔的字符串)")
private String publicityImage;
@@ -99,13 +97,13 @@ public class TraceabilityCodeSaveReqVO {
private List<String> publicityImageList;
@Schema(description = "是否显示宣传图片")
private Long isShowPublicityImage;
private Boolean isShowPublicityImage;
@Schema(description = "企业简介")
private String publicityProfile;
@Schema(description = "是否显示企业简介")
private Long isShowPublicityProfile;
private Boolean isShowPublicityProfile;
@Schema(description = "批次检验报告")
private String inspectionReport;
@@ -129,4 +127,102 @@ public class TraceabilityCodeSaveReqVO {
private Long status;
private String codeOutBatch;
private Long scanCodeCount;
// ========== 新增字段支持复杂JSON结构 ==========
@Schema(description = "农事记录列表")
private List<FarmingInputItem> farmingInputList;
@Schema(description = "品牌认证列表")
private List<String> brandAuthentication;
@Schema(description = "检验报告列表")
private List<String> inspectionReportList;
@Schema(description = "计量单位", example = "3")
private String measuringUnit;
@Schema(description = "包装单位", example = "8")
private String packingUnit;
@Schema(description = "自定义数据列表")
private List<CustomDataItem> customData;
@Schema(description = "是否显示基地")
private Boolean isShowBase;
@Schema(description = "农事记录项")
@Data
public static class FarmingInputItem {
@Schema(description = "农事名称", example = "123")
private String farmingName;
@Schema(description = "农事日期列表")
private List<String> date;
@Schema(description = "投入品列表")
private List<InputItem> inputList;
@Schema(description = "农事图片列表")
private List<String> imageList;
}
@Schema(description = "投入品项")
@Data
public static class InputItem {
@Schema(description = "投入品ID", example = "97e9f792-3b84-4132-9350-b08f34641c65")
private String inputsId;
@Schema(description = "资产类型", example = "2")
private Integer assetType;
@Schema(description = "用量", example = "100")
private java.math.BigDecimal dose;
@Schema(description = "单位", example = "6")
private Integer unit;
@Schema(description = "包装单位", example = "1")
private Integer packageUnit;
@Schema(description = "稀释倍液", example = "1.5倍")
private String diluted;
@Schema(description = "用法", example = "123")
private String usage;
@Schema(description = "投入品名称", example = "药物")
private String inputsName;
@Schema(description = "单位名称")
private String unitName;
@Schema(description = "包装单位名称")
private String packageUnitName;
}
@Schema(description = "自定义数据项")
@Data
public static class CustomDataItem {
@Schema(description = "链接名称")
private String linkName;
@Schema(description = "自定义区块列表")
private List<CustomSection> customSection;
@Schema(description = "自定义区块")
@Data
public static class CustomSection {
@Schema(description = "标签")
private String label;
@Schema(description = "类型")
private Integer type;
@Schema(description = "内容")
private String content;
@Schema(description = "图片列表")
private List<String> imageList;
}
}
}

View File

@@ -1,19 +1,17 @@
package cn.iocoder.yudao.module.farm.dal.dataobject.traceabilitycode;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import cn.iocoder.yudao.module.farm.framework.util.ImageCollectionUtil;
import com.baomidou.mybatisplus.annotation.*;
import lombok.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import cn.iocoder.yudao.module.farm.framework.util.ImageCollectionUtil;
/**
* 溯源-溯源码 DO
* 溯源-溯源码 DO
*
* @author 芋道源码
*/
@@ -57,9 +55,15 @@ public class TraceabilityCodeDO extends BaseDO {
*/
private String plotName;
/**
* 采收时间
* 采收时间(数据库存储为逗号分隔的字符串)
*/
private LocalDateTime harvestDate;
private String harvestDate;
/**
* 采收时间集合(业务层使用)
*/
@TableField(exist = false)
private List<String> harvestDateList;
/**
* 农事记录
*/
@@ -99,7 +103,7 @@ public class TraceabilityCodeDO extends BaseDO {
/**
* 商品认证
*/
private String brandAuthentication;
private String brandAuthenticationStr;
/**
* 企业id
*/
@@ -199,6 +203,32 @@ public class TraceabilityCodeDO extends BaseDO {
private Long scanCodeCount;
// ========== 新增字段支持复杂JSON结构 ==========
/**
* 农事记录JSON数据(存储复杂的农事记录结构)
*/
private String farmingInputJson;
/**
* 自定义数据JSON(存储自定义字段数据)
*/
private String customDataJson;
/**
* 计量单位
*/
private Integer measuringUnit;
/**
* 包装单位
*/
private Integer packingUnit;
/**
* 是否显示基地
*/
private Long isShowBase;
/**
* 获取商品图片集合
*/
@@ -252,4 +282,54 @@ public class TraceabilityCodeDO extends BaseDO {
this.collectImagesList = collectImagesList;
this.collectImages = ImageCollectionUtil.toDatabaseString(collectImagesList);
}
/**
* 获取农事记录JSON数据
*/
public String getFarmingInputJson() {
return farmingInputJson;
}
/**
* 设置农事记录JSON数据
*/
public void setFarmingInputJson(String farmingInputJson) {
this.farmingInputJson = farmingInputJson;
}
/**
* 获取自定义数据JSON
*/
public String getCustomDataJson() {
return customDataJson;
}
/**
* 设置自定义数据JSON
*/
public void setCustomDataJson(String customDataJson) {
this.customDataJson = customDataJson;
}
/**
* 获取采收时间集合
*/
public List<String> getHarvestDateList() {
if (harvestDateList == null && harvestDate != null) {
harvestDateList = Arrays.asList(harvestDate.split(","));
}
return harvestDateList;
}
/**
* 设置采收时间集合
*/
public void setHarvestDateList(List<String> harvestDateList) {
this.harvestDateList = harvestDateList;
if (harvestDateList != null && !harvestDateList.isEmpty()) {
this.harvestDate = String.join(",", harvestDateList);
} else {
this.harvestDate = null;
}
}
}

View File

@@ -24,7 +24,9 @@ public interface TraceabilityCodeMapper extends BaseMapperX<TraceabilityCodeDO>
.eqIfPresent(TraceabilityCodeDO::getPlotId, reqVO.getPlotId())
.likeIfPresent(TraceabilityCodeDO::getPlotName, reqVO.getPlotName())
.eqIfPresent(TraceabilityCodeDO::getTenantId, reqVO.getTenantId())
.betweenIfPresent(TraceabilityCodeDO::getHarvestDate, reqVO.getHarvestDate())
// 采收时间范围查询
.gtIfPresent(TraceabilityCodeDO::getHarvestDate, reqVO.getHarvestDateStart())
.leIfPresent(TraceabilityCodeDO::getHarvestDate, reqVO.getHarvestDateEnd())
.eqIfPresent(TraceabilityCodeDO::getFarmingInputCount, reqVO.getFarmingInputCount())
.eqIfPresent(TraceabilityCodeDO::getProductId, reqVO.getProductId())
.likeIfPresent(TraceabilityCodeDO::getProductName, reqVO.getProductName())
@@ -32,7 +34,7 @@ public interface TraceabilityCodeMapper extends BaseMapperX<TraceabilityCodeDO>
.eqIfPresent(TraceabilityCodeDO::getProductImage, reqVO.getProductImage())
.likeIfPresent(TraceabilityCodeDO::getBrandName, reqVO.getBrandName())
.eqIfPresent(TraceabilityCodeDO::getIntroduce, reqVO.getIntroduce())
.eqIfPresent(TraceabilityCodeDO::getBrandAuthentication, reqVO.getBrandAuthentication())
.eqIfPresent(TraceabilityCodeDO::getBrandAuthenticationStr, reqVO.getBrandAuthentication())
.eqIfPresent(TraceabilityCodeDO::getBusinessId, reqVO.getBusinessId())
.likeIfPresent(TraceabilityCodeDO::getBusinessName, reqVO.getBusinessName())
.eqIfPresent(TraceabilityCodeDO::getIsShowBusinessName, reqVO.getIsShowBusinessName())

View File

@@ -0,0 +1,132 @@
package cn.iocoder.yudao.module.farm.framework.util;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.module.farm.controller.admin.traceabilitycode.vo.TraceabilityCodeRespVO;
import cn.iocoder.yudao.module.farm.dal.dataobject.traceabilitycode.TraceabilityCodeDO;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 溯源数据转换工具类
* 用于统一返回数据格式
*
* @author 芋道源码
*/
public class TraceabilityDataConverter {
/**
* 将DO对象转换为RespVO对象,统一返回数据格式
*
* @param traceabilityCodeDO 数据库对象
* @return 响应VO对象
*/
public static TraceabilityCodeRespVO convertToRespVO(TraceabilityCodeDO traceabilityCodeDO) {
if (traceabilityCodeDO == null) {
return null;
}
TraceabilityCodeRespVO respVO = new TraceabilityCodeRespVO();
// 基本信息映射
respVO.setId(traceabilityCodeDO.getId());
respVO.setSpeciesCode(traceabilityCodeDO.getSpeciesCode());
respVO.setSpeciesName(traceabilityCodeDO.getSpeciesName());
respVO.setBaseId(traceabilityCodeDO.getBaseId());
respVO.setBaseName(traceabilityCodeDO.getBaseName());
respVO.setPlotId(traceabilityCodeDO.getPlotId());
respVO.setPlotName(traceabilityCodeDO.getPlotName());
respVO.setTenantId(traceabilityCodeDO.getTenantId());
respVO.setHarvestDate(traceabilityCodeDO.getHarvestDate());
respVO.setFarmingInputCount(traceabilityCodeDO.getFarmingInputCount());
respVO.setProductId(traceabilityCodeDO.getProductId());
respVO.setProductName(traceabilityCodeDO.getProductName());
respVO.setPackingSpec(traceabilityCodeDO.getPackingSpec());
respVO.setProductImage(traceabilityCodeDO.getProductImage());
respVO.setProductImageList(traceabilityCodeDO.getProductImageList());
respVO.setBrandName(traceabilityCodeDO.getBrandName());
respVO.setIntroduce(traceabilityCodeDO.getIntroduce());
respVO.setBusinessId(traceabilityCodeDO.getBusinessId());
respVO.setBusinessName(traceabilityCodeDO.getBusinessName());
respVO.setBusinessPhone(traceabilityCodeDO.getBusinessPhone());
respVO.setStoreName(traceabilityCodeDO.getStoreName());
respVO.setBusinessAddress(traceabilityCodeDO.getBusinessAddress());
respVO.setPublicityImage(traceabilityCodeDO.getPublicityImage());
respVO.setPublicityImageList(traceabilityCodeDO.getPublicityImageList());
respVO.setPublicityProfile(traceabilityCodeDO.getPublicityProfile());
respVO.setInspectionReport(traceabilityCodeDO.getInspectionReport());
respVO.setCollectImages(traceabilityCodeDO.getCollectImages());
respVO.setCollectImagesList(traceabilityCodeDO.getCollectImagesList());
respVO.setCameraInformation(traceabilityCodeDO.getCameraInformation());
respVO.setCodeOutCount(traceabilityCodeDO.getCodeOutCount());
respVO.setQrCode(traceabilityCodeDO.getQrCode());
respVO.setStatus(traceabilityCodeDO.getStatus());
respVO.setCreateTime(traceabilityCodeDO.getCreateTime());
respVO.setCodeOutBatch(traceabilityCodeDO.getCodeOutBatch());
respVO.setScanCodeCount(traceabilityCodeDO.getScanCodeCount());
// 统一显示标志格式:Long -> Boolean
respVO.setIsShowBusinessName(convertLongToBoolean(traceabilityCodeDO.getIsShowBusinessName()));
respVO.setIsShowBusinessPhone(convertLongToBoolean(traceabilityCodeDO.getIsShowBusinessPhone()));
respVO.setIsShowStoreName(convertLongToBoolean(traceabilityCodeDO.getIsShowStoreName()));
respVO.setIsShowBusinessAddress(convertLongToBoolean(traceabilityCodeDO.getIsShowBusinessAddress()));
respVO.setIsShowPublicityImage(convertLongToBoolean(traceabilityCodeDO.getIsShowPublicityImage()));
respVO.setIsShowPublicityProfile(convertLongToBoolean(traceabilityCodeDO.getIsShowPublicityProfile()));
respVO.setIsShowBase(convertLongToBoolean(traceabilityCodeDO.getIsShowBase()));
// 处理复杂数据结构
respVO.setFarmingInputJson(traceabilityCodeDO.getFarmingInputJson());
respVO.setCustomDataJson(traceabilityCodeDO.getCustomDataJson());
respVO.setMeasuringUnit(traceabilityCodeDO.getMeasuringUnit());
respVO.setPackingUnit(traceabilityCodeDO.getPackingUnit());
// 解析品牌认证列表
if (StrUtil.isNotBlank(traceabilityCodeDO.getBrandAuthenticationStr())) {
respVO.setBrandAuthentication(Arrays.asList(traceabilityCodeDO.getBrandAuthenticationStr().split(",")));
}
// 解析检验报告列表
if (StrUtil.isNotBlank(traceabilityCodeDO.getInspectionReport())) {
respVO.setInspectionReportList(Arrays.asList(traceabilityCodeDO.getInspectionReport().split(",")));
}
// 解析农事记录列表
if (StrUtil.isNotBlank(traceabilityCodeDO.getFarmingInputJson())) {
try {
List<TraceabilityCodeRespVO.FarmingInputItem> farmingInputList =
JSONUtil.toList(traceabilityCodeDO.getFarmingInputJson(), TraceabilityCodeRespVO.FarmingInputItem.class);
respVO.setFarmingInputList(farmingInputList);
} catch (Exception e) {
// 解析失败,保持为空
}
}
// 解析自定义数据列表
if (StrUtil.isNotBlank(traceabilityCodeDO.getCustomDataJson())) {
try {
List<TraceabilityCodeRespVO.CustomDataItem> customDataList =
JSONUtil.toList(traceabilityCodeDO.getCustomDataJson(), TraceabilityCodeRespVO.CustomDataItem.class);
respVO.setCustomData(customDataList);
} catch (Exception e) {
// 解析失败,保持为空
}
}
return respVO;
}
/**
* 将Long类型转换为Boolean类型
*
* @param value Long值
* @return Boolean值
*/
private static Boolean convertLongToBoolean(Long value) {
if (value == null) {
return null;
}
return value == 1L;
}
}

View File

@@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.farm.service.traceabilitycode;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser;
@@ -8,7 +10,6 @@ import cn.iocoder.yudao.module.farm.controller.admin.traceabilitycode.vo.Traceab
import cn.iocoder.yudao.module.farm.controller.admin.traceabilitycode.vo.TraceabilityCodeSaveReqVO;
import cn.iocoder.yudao.module.farm.dal.dataobject.traceabilitycode.TraceabilityCodeDO;
import cn.iocoder.yudao.module.farm.dal.mysql.traceabilitycode.TraceabilityCodeMapper;
import cn.iocoder.yudao.module.farm.framework.util.ImageCollectionUtil;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@@ -97,6 +98,9 @@ public class TraceabilityCodeServiceImpl implements TraceabilityCodeService {
traceabilityCode.getProductImageList();
traceabilityCode.getPublicityImageList();
traceabilityCode.getCollectImagesList();
// 处理复杂数据结构的解析
parseComplexDataFromDatabase(traceabilityCode);
}
return traceabilityCode;
}
@@ -111,6 +115,9 @@ public class TraceabilityCodeServiceImpl implements TraceabilityCodeService {
traceabilityCode.getProductImageList();
traceabilityCode.getPublicityImageList();
traceabilityCode.getCollectImagesList();
// 处理复杂数据结构的解析
parseComplexDataFromDatabase(traceabilityCode);
}
});
}
@@ -150,5 +157,135 @@ public class TraceabilityCodeServiceImpl implements TraceabilityCodeService {
} else if (reqVO.getCollectImages() != null) {
traceabilityCode.setCollectImages(reqVO.getCollectImages());
}
// 处理Boolean到Long的类型转换
convertBooleanToLong(traceabilityCode, reqVO);
// 处理复杂数据结构转换
handleComplexDataConversion(traceabilityCode, reqVO);
}
/**
* 处理复杂数据结构转换
* 将复杂的嵌套结构序列化为JSON字符串存储到数据库
*/
private void handleComplexDataConversion(TraceabilityCodeDO traceabilityCode, TraceabilityCodeSaveReqVO reqVO) {
// 处理农事记录列表
if (reqVO.getFarmingInputList() != null && !reqVO.getFarmingInputList().isEmpty()) {
String farmingInputJson = JSONUtil.toJsonStr(reqVO.getFarmingInputList());
// 将农事记录JSON存储到专门的字段
traceabilityCode.setFarmingInputJson(farmingInputJson);
// 同时存储到cameraInformation字段以保持兼容性
traceabilityCode.setCameraInformation(farmingInputJson);
}
// 处理品牌认证列表
if (reqVO.getBrandAuthentication() != null && !reqVO.getBrandAuthentication().isEmpty()) {
String brandAuthStr = String.join(",", reqVO.getBrandAuthentication());
traceabilityCode.setBrandAuthenticationStr(brandAuthStr);
}
// 处理检验报告列表
if (reqVO.getInspectionReportList() != null && !reqVO.getInspectionReportList().isEmpty()) {
String inspectionReportStr = String.join(",", reqVO.getInspectionReportList());
traceabilityCode.setInspectionReport(inspectionReportStr);
}
// 处理自定义数据
if (reqVO.getCustomData() != null && !reqVO.getCustomData().isEmpty()) {
String customDataJson = JSONUtil.toJsonStr(reqVO.getCustomData());
// 存储到专门的字段
traceabilityCode.setCustomDataJson(customDataJson);
}
// 处理新增的字段
if (CharSequenceUtil.isNotBlank(reqVO.getMeasuringUnit())) {
try {
traceabilityCode.setMeasuringUnit(Integer.valueOf(reqVO.getMeasuringUnit()));
} catch (NumberFormatException e) {
// 忽略无效的数字格式
}
}
if (CharSequenceUtil.isNotBlank(reqVO.getPackingUnit())) {
try {
traceabilityCode.setPackingUnit(Integer.valueOf(reqVO.getPackingUnit()));
} catch (NumberFormatException e) {
// 忽略无效的数字格式
}
}
// isShowBase字段已经在convertBooleanToLong方法中处理了
}
/**
* 处理Boolean到Long的类型转换
* 将VO中的Boolean字段转换为DO中的Long字段
*/
private void convertBooleanToLong(TraceabilityCodeDO traceabilityCode, TraceabilityCodeSaveReqVO reqVO) {
// 转换显示标志字段
if (reqVO.getIsShowBusinessName() != null) {
traceabilityCode.setIsShowBusinessName(reqVO.getIsShowBusinessName() ? 1L : 0L);
}
if (reqVO.getIsShowBusinessPhone() != null) {
traceabilityCode.setIsShowBusinessPhone(reqVO.getIsShowBusinessPhone() ? 1L : 0L);
}
if (reqVO.getIsShowStoreName() != null) {
traceabilityCode.setIsShowStoreName(reqVO.getIsShowStoreName() ? 1L : 0L);
}
if (reqVO.getIsShowBusinessAddress() != null) {
traceabilityCode.setIsShowBusinessAddress(reqVO.getIsShowBusinessAddress() ? 1L : 0L);
}
if (reqVO.getIsShowPublicityProfile() != null) {
traceabilityCode.setIsShowPublicityProfile(reqVO.getIsShowPublicityProfile() ? 1L : 0L);
}
if (reqVO.getIsShowPublicityImage() != null) {
traceabilityCode.setIsShowPublicityImage(reqVO.getIsShowPublicityImage() ? 1L : 0L);
}
if (reqVO.getIsShowBase() != null) {
traceabilityCode.setIsShowBase(reqVO.getIsShowBase() ? 1L : 0L);
}
}
/**
* 从数据库解析复杂数据结构
* 将存储的JSON字符串解析为对象属性,并统一返回数据格式
*/
private void parseComplexDataFromDatabase(TraceabilityCodeDO traceabilityCode) {
// 解析农事记录JSON数据
if (CharSequenceUtil.isNotBlank(traceabilityCode.getCameraInformation())) {
String cameraInfo = traceabilityCode.getCameraInformation();
// 检查是否是JSON格式的农事记录数据
if (cameraInfo.startsWith("{") || cameraInfo.startsWith("[")) {
traceabilityCode.setFarmingInputJson(cameraInfo);
}
}
// 解析品牌认证列表
if (CharSequenceUtil.isNotBlank(traceabilityCode.getBrandAuthenticationStr())) {
// 品牌认证已经是逗号分隔的字符串,不需要额外处理
}
// 解析检验报告列表
if (CharSequenceUtil.isNotBlank(traceabilityCode.getInspectionReport())) {
// 检验报告已经是逗号分隔的字符串,不需要额外处理
}
// 统一返回数据格式:将Long类型的显示标志转换为Boolean类型
convertLongToBoolean(traceabilityCode);
}
/**
* 将DO中的Long字段转换为Boolean字段,统一返回数据格式
*/
private void convertLongToBoolean(TraceabilityCodeDO traceabilityCode) {
// 这里我们不需要实际转换,因为DO对象保持Long类型用于数据库存储
// 转换将在VO层进行,确保前端接收到的是Boolean类型
}
}

View File

@@ -0,0 +1,41 @@
-- 为 farm_traceability_code 表添加 JSON 字段
-- 用于存储复杂的农事记录和自定义数据
-- MySQL 版本
ALTER TABLE farm_traceability_code
ADD COLUMN farming_input_json TEXT COMMENT '农事记录JSON数据(存储复杂的农事记录结构)',
ADD COLUMN custom_data_json TEXT COMMENT '自定义数据JSON(存储自定义字段数据)',
ADD COLUMN measuring_unit INT COMMENT '计量单位',
ADD COLUMN packing_unit INT COMMENT '包装单位',
ADD COLUMN is_show_base BIGINT COMMENT '是否显示基地';
-- PostgreSQL 版本
-- ALTER TABLE farm_traceability_code
-- ADD COLUMN farming_input_json TEXT,
-- ADD COLUMN custom_data_json TEXT,
-- ADD COLUMN measuring_unit INTEGER,
-- ADD COLUMN packing_unit INTEGER,
-- ADD COLUMN is_show_base BIGINT;
-- Oracle 版本
-- ALTER TABLE farm_traceability_code
-- ADD (farming_input_json CLOB,
-- custom_data_json CLOB,
-- measuring_unit NUMBER(10),
-- packing_unit NUMBER(10),
-- is_show_base NUMBER(19));
-- SQL Server 版本
-- ALTER TABLE farm_traceability_code
-- ADD farming_input_json NVARCHAR(MAX),
-- custom_data_json NVARCHAR(MAX),
-- measuring_unit INT,
-- packing_unit INT,
-- is_show_base BIGINT;
-- 添加索引以提高查询性能
CREATE INDEX idx_farm_traceability_code_farming_input_json ON farm_traceability_code(farming_input_json(100));
CREATE INDEX idx_farm_traceability_code_custom_data_json ON farm_traceability_code(custom_data_json(100));
CREATE INDEX idx_farm_traceability_code_measuring_unit ON farm_traceability_code(measuring_unit);
CREATE INDEX idx_farm_traceability_code_packing_unit ON farm_traceability_code(packing_unit);
CREATE INDEX idx_farm_traceability_code_is_show_base ON farm_traceability_code(is_show_base);

View File

@@ -0,0 +1,225 @@
### 创建溯源-溯源码(支持新的复杂JSON结构)
POST http://localhost:8080/admin-api/farm/traceability-code/create
Content-Type: application/json
Authorization: Bearer {{token}}
{
"speciesCode": "",
"speciesName": "绿水稻",
"businessId": "027fef60-72c7-4b16-aad7-74bd4e7c492d",
"businessName": "测试",
"businessPhone": "19995432633",
"storeName": "123",
"businessAddress": "123",
"publicityProfile": "123",
"publicityImageList": [
"http://223.83.152.93:9000/farm/20250826/b569169d762c4c74bcb5b007be492060_1756207500866.png",
"http://223.83.152.93:9000/farm/20250826/b569169d762c4c74bcb5b007be492060_1756207885105.png"
],
"isShowBusinessName": true,
"isShowBusinessPhone": true,
"isShowStoreName": true,
"isShowBusinessAddress": true,
"isShowPublicityProfile": true,
"isShowPublicityImage": true,
"productId": "64fcede4-247b-437d-93be-b7c9d636e6ce",
"productName": "红薯干",
"baseId": "",
"baseName": "测试基地1",
"isShowBase": true,
"harvestDate": "2025-09-01 00:00:00",
"farmingInputCount": 1,
"farmingInputList": [
{
"farmingName": "123",
"date": ["2025-08-31", "2025-09-01"],
"inputList": [
{
"inputsId": "97e9f792-3b84-4132-9350-b08f34641c65",
"assetType": 2,
"dose": 100,
"unit": 6,
"packageUnit": 1,
"diluted": "1.5倍",
"usage": "123",
"inputsName": "药物",
"unitName": null,
"packageUnitName": null
}
],
"imageList": []
}
],
"productImage": "",
"brandAuthentication": ["1", "2", "3", "4"],
"inspectionReport": "",
"inspectionReportList": [],
"collectImages": "",
"collectImagesList": [],
"measuringUnit": "2",
"packingUnit": "2",
"customData": [
{
"linkName": "123",
"customSection": [
{
"label": "123",
"type": 1,
"content": "123",
"imageList": []
},
{
"label": "456",
"type": 2,
"content": "456",
"imageList": [
"http://example.com/image1.jpg",
"http://example.com/image2.jpg"
]
}
]
},
{
"linkName": "789",
"customSection": [
{
"label": "789",
"type": 1,
"content": "789",
"imageList": []
}
]
}
],
"codeOutCount": 1,
"cameraInformation": null,
"packingSpec": "10",
"brandName": "红薯干",
"introduce": "好吃的红薯干哦"
}
### 更新溯源-溯源码(支持新的复杂JSON结构)
PUT http://localhost:8080/admin-api/farm/traceability-code/update
Content-Type: application/json
Authorization: Bearer {{token}}
{
"id": "{{traceabilityCodeId}}",
"speciesCode": "",
"speciesName": "绿水稻",
"businessId": "027fef60-72c7-4b16-aad7-74bd4e7c492d",
"businessName": "测试企业",
"businessPhone": "19995432633",
"storeName": "测试网店",
"businessAddress": "测试地址",
"publicityProfile": "测试企业简介",
"publicityImageList": [
"http://223.83.152.93:9000/farm/20250826/b569169d762c4c74bcb5b007be492060_1756207500866.png"
],
"isShowBusinessName": true,
"isShowBusinessPhone": true,
"isShowStoreName": true,
"isShowBusinessAddress": true,
"isShowPublicityProfile": true,
"isShowPublicityImage": true,
"productId": "64fcede4-247b-437d-93be-b7c9d636e6ce",
"productName": "红薯干",
"baseId": "",
"baseName": "测试基地1",
"isShowBase": true,
"harvestDate": "2025-09-01 00:00:00",
"farmingInputCount": 2,
"farmingInputList": [
{
"farmingName": "施肥",
"date": ["2025-08-31", "2025-09-01"],
"inputList": [
{
"inputsId": "97e9f792-3b84-4132-9350-b08f34641c65",
"assetType": 2,
"dose": 100,
"unit": 6,
"packageUnit": 1,
"diluted": "1.5倍",
"usage": "叶面喷施",
"inputsName": "药物",
"unitName": "毫升",
"packageUnitName": "瓶"
}
],
"imageList": []
},
{
"farmingName": "浇水",
"date": ["2025-09-02"],
"inputList": [],
"imageList": []
}
],
"productImage": "",
"brandAuthentication": ["有机认证", "绿色食品认证", "无公害认证"],
"inspectionReport": "",
"inspectionReportList": ["报告1.pdf", "报告2.pdf"],
"collectImages": "",
"collectImagesList": [],
"measuringUnit": "2",
"packingUnit": "2",
"customData": [
{
"linkName": "产品特色",
"customSection": [
{
"label": "产地特色",
"type": 1,
"content": "来自四川优质红薯产区",
"imageList": []
},
{
"label": "制作工艺",
"type": 2,
"content": "传统手工制作,无添加",
"imageList": [
"http://example.com/process1.jpg",
"http://example.com/process2.jpg"
]
}
]
},
{
"linkName": "营养价值",
"customSection": [
{
"label": "营养成分",
"type": 1,
"content": "富含膳食纤维和维生素",
"imageList": []
}
]
}
],
"codeOutCount": 1,
"cameraInformation": null,
"packingSpec": "10",
"brandName": "红薯干",
"introduce": "好吃的红薯干哦,营养丰富,口感香甜"
}
### 获取溯源-溯源码详情
GET http://localhost:8080/admin-api/farm/traceability-code/get?id={{traceabilityCodeId}}
Authorization: Bearer {{token}}
### 获取溯源-溯源码分页
GET http://localhost:8080/admin-api/farm/traceability-code/page?pageNo=1&pageSize=10
Authorization: Bearer {{token}}
### 扫描溯源码
GET http://localhost:8080/admin-api/farm/traceability-code/scan?id={{traceabilityCodeId}}
Authorization: Bearer {{token}}
### 删除溯源-溯源码
DELETE http://localhost:8080/admin-api/farm/traceability-code/delete?id={{traceabilityCodeId}}
Authorization: Bearer {{token}}
### 批量删除溯源-溯源码
DELETE http://localhost:8080/admin-api/farm/traceability-code/delete-list?ids={{traceabilityCodeId1}},{{traceabilityCodeId2}}
Authorization: Bearer {{token}}