Commit 05642cf7 by Lizh

迁移/api/product/template/get接口

parent 9d8ade8c
...@@ -15,4 +15,5 @@ ...@@ -15,4 +15,5 @@
.claude/ .claude/
CLAUDE.md CLAUDE.md
docs docs
plans
package com.jomalls.custom.app.service;
import com.jomalls.custom.app.vo.BindDetailVO;
import com.jomalls.custom.app.vo.ProductTemplateInfoSnakeVO;
/**
* 产品模板信息服务接口
* <p>
* 对齐 TS 项目 {@code ProductTemplateInfoService} 的 getByIdOrSku 和 bindDetail 方法。
*
* @author Lizh
* @date 2026-06-17
*/
public interface ProductTemplateInfoService {
/**
* 根据 ID 或 SKU 获取模板完整数据(含属性解析和规格加载)
*
* @param id 模板 ID(可选)
* @param sku 模板 SKU(可选)
* @return 模板完整 VO,包含明细、备注、属性、规格等
*/
ProductTemplateInfoSnakeVO getByIdOrSku(Integer id, String sku);
/**
* 查看模板与商品的绑定详情
* <p>
* 返回绑定的商品信息 + 模板明细与商品明细的关联列表。
*
* @param id 模板 ID(可选)
* @param sku 模板 SKU(可选)
* @return 绑定详情 VO
*/
BindDetailVO bindDetail(Integer id, String sku);
}
...@@ -410,7 +410,13 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService { ...@@ -410,7 +410,13 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
CustomProductInfoEntity entity = validateAndQueryEntity(id, sku); CustomProductInfoEntity entity = validateAndQueryEntity(id, sku);
final Integer productId = entity.getId(); final Integer productId = entity.getId();
// 2. 查询用户(如果指定了 namespace) // 2. 查询用户(如果指定了 namespace)
DbDiyUserEntity user = diyUserService.getByNamespace(namespace); DbDiyUserEntity user = null;
if (StringUtils.isNotBlank(namespace)) {
user = diyUserService.getByNamespace(namespace);
if (user == null) {
throw new ServiceException("用户不存在");
}
}
// 3. 并行查询所有子表数据 // 3. 并行查询所有子表数据
ProductRelatedData relatedData = queryRelatedDataInParallel(productId); ProductRelatedData relatedData = queryRelatedDataInParallel(productId);
// 4. 组合完整 VO // 4. 组合完整 VO
......
...@@ -5,10 +5,13 @@ import com.jomalls.custom.app.exception.ServiceException; ...@@ -5,10 +5,13 @@ import com.jomalls.custom.app.exception.ServiceException;
import com.jomalls.custom.app.service.CustomProductItemService; import com.jomalls.custom.app.service.CustomProductItemService;
import com.jomalls.custom.app.service.DiyUserService; import com.jomalls.custom.app.service.DiyUserService;
import com.jomalls.custom.app.utils.BeanMapper; import com.jomalls.custom.app.utils.BeanMapper;
import com.jomalls.custom.app.vo.CustomProductFactoryPriceRelSnakeVO;
import com.jomalls.custom.app.vo.CustomProductInfoSnakeVO;
import com.jomalls.custom.app.vo.CustomProductItemSnakeVO; import com.jomalls.custom.app.vo.CustomProductItemSnakeVO;
import com.jomalls.custom.dal.entity.*; import com.jomalls.custom.dal.entity.*;
import com.jomalls.custom.domain.service.*; import com.jomalls.custom.domain.service.*;
import com.jomalls.custom.security.SecurityUtils; import com.jomalls.custom.security.SecurityUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -41,6 +44,7 @@ public class CustomProductItemServiceImpl implements CustomProductItemService { ...@@ -41,6 +44,7 @@ public class CustomProductItemServiceImpl implements CustomProductItemService {
private final LogCustomProductDomainService logCustomProductDomainService; private final LogCustomProductDomainService logCustomProductDomainService;
private final LogProductTemplateDomainService logProductTemplateDomainService; private final LogProductTemplateDomainService logProductTemplateDomainService;
private final DiyUserService diyUserService; private final DiyUserService diyUserService;
private final CustomProductFactoryPriceRelDomainService customProductFactoryPriceRelDomainService;
private final TransactionTemplate transactionTemplate; private final TransactionTemplate transactionTemplate;
...@@ -228,40 +232,77 @@ public class CustomProductItemServiceImpl implements CustomProductItemService { ...@@ -228,40 +232,77 @@ public class CustomProductItemServiceImpl implements CustomProductItemService {
throw new ServiceException("SKU不能为空"); throw new ServiceException("SKU不能为空");
} }
// ① 查询明细(含关联商品信息的工厂字段)(对齐 TS:152-157 // ① 查询明细(含关联商品信息的工厂字段)(对齐 TS:152-153 include CustomProductInfo
List<CustomProductItemEntity> items = customProductItemDomainService.selectBySkusWithInfo(skus); List<CustomProductItemEntity> items = customProductItemDomainService.selectBySkusWithInfo(skus);
if (CollectionUtils.isEmpty(items)) {
// ② 如果传了 namespace,查询用户并应用折扣(对齐 TS:165-174) return Collections.emptyList();
if (StringUtils.hasText(namespace)) {
DbDiyUserEntity user = diyUserService.getByNamespace(namespace);
if (user == null) {
throw new ServiceException("用户信息不存在");
}
// 计算用户折扣率(对齐 TS:357-360)
BigDecimal discountBase = new BigDecimal("100");
BigDecimal discountRate = user.getDiscount() != null
? user.getDiscount().divide(discountBase, 4, RoundingMode.HALF_UP)
: BigDecimal.ONE;
if (discountRate.compareTo(BigDecimal.ONE) != 0) {
for (CustomProductItemEntity item : items) {
if (item.getSalesPrice() != null) {
item.setSalesPrice(item.getSalesPrice().multiply(discountRate)
.setScale(2, RoundingMode.HALF_UP));
}
} }
// ② 批量查询关联的 CustomProductInfo 和 CustomProductFactoryPriceRel
Set<Integer> productIds = items.stream()
.map(CustomProductItemEntity::getProductId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
Set<Integer> itemIds = items.stream()
.map(CustomProductItemEntity::getId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
// 商品信息 Map(key = productId)
Map<Integer, CustomProductInfoEntity> productInfoMap;
if (!productIds.isEmpty()) {
List<CustomProductInfoEntity> productInfos = customProductInfoDomainService.listByIds(productIds);
productInfoMap = productInfos.stream()
.collect(Collectors.toMap(CustomProductInfoEntity::getId, p -> p, (a, b) -> a));
} else {
productInfoMap = Collections.emptyMap();
} }
// 工厂价格 Map(key = itemId → list)(对齐 TS:153 include CustomProductFactoryPriceRel)
Map<Integer, List<CustomProductFactoryPriceRelEntity>> factoryPriceMap;
if (!itemIds.isEmpty()) {
List<CustomProductFactoryPriceRelEntity> allFactoryPrices = customProductFactoryPriceRelDomainService
.list(new LambdaQueryWrapper<CustomProductFactoryPriceRelEntity>()
.in(CustomProductFactoryPriceRelEntity::getItemId, itemIds));
factoryPriceMap = allFactoryPrices.stream()
.collect(Collectors.groupingBy(CustomProductFactoryPriceRelEntity::getItemId));
} else {
factoryPriceMap = Collections.emptyMap();
} }
// ③ 转换实体为响应 VO,附加工厂信息和 print_type(对齐 TS:158-164) // ③ 如果传了 namespace,查询用户(对齐 TS:165-168)
final DbDiyUserEntity user = StringUtils.hasText(namespace)
? resolveUser(namespace) : null;
// ④ 转换实体为响应 VO(对齐 TS:158-164 + include 关联数据)
return items.stream().map(item -> { return items.stream().map(item -> {
CustomProductItemSnakeVO vo = BeanMapper.snakeCase().convert(item, CustomProductItemSnakeVO.class); CustomProductItemSnakeVO vo = BeanMapper.snakeCase().convert(item, CustomProductItemSnakeVO.class);
// 附加工厂信息(来自 JOIN custom_product_info) // 附加工厂信息(来自 JOIN custom_product_info)
vo.setFactory_id(item.getInfoFactoryId()); vo.setFactory_id(item.getInfoFactoryId());
vo.setFactory_code(item.getInfoFactoryCode()); vo.setFactory_code(item.getInfoFactoryCode());
// print_type 使用商品主表的 print_type 覆盖明细自身的(对齐 TS: temp.print_type = item.customProductInfo?.print_type) // print_type 使用商品主表的 print_type 覆盖(对齐 TS: temp.print_type = item.customProductInfo?.print_type)
if (item.getInfoPrintType() != null) { if (item.getInfoPrintType() != null) {
vo.setPrint_type(item.getInfoPrintType()); vo.setPrint_type(item.getInfoPrintType());
} }
// 填充 customProductInfo(对齐 TS include CustomProductInfo)
CustomProductInfoEntity productInfo = productInfoMap.get(item.getProductId());
final CustomProductInfoSnakeVO productInfoVO = productInfo != null
? buildProductInfoVO(productInfo) : null;
// 填充 factoryPriceList(对齐 TS include CustomProductFactoryPriceRel)
List<CustomProductFactoryPriceRelEntity> factoryPrices = factoryPriceMap
.getOrDefault(item.getId(), Collections.emptyList());
final List<CustomProductFactoryPriceRelSnakeVO> factoryPriceVOList = BeanMapper.snakeCase()
.convertList(factoryPrices, CustomProductFactoryPriceRelSnakeVO.class);
// 应用用户折扣(对齐 TS:169-174 setProductItemExternalPrice)
if (user != null) {
diyUserService.setProductItemExternalPrice(user, vo, factoryPriceVOList, productInfoVO);
}
vo.setCustomProductInfo(productInfoVO);
vo.setFactoryPriceList(factoryPriceVOList);
return vo; return vo;
}).collect(Collectors.toList()); }).collect(Collectors.toList());
} }
...@@ -291,4 +332,27 @@ public class CustomProductItemServiceImpl implements CustomProductItemService { ...@@ -291,4 +332,27 @@ public class CustomProductItemServiceImpl implements CustomProductItemService {
log.setCreateTime(new Date()); log.setCreateTime(new Date());
logProductTemplateDomainService.save(log); logProductTemplateDomainService.save(log);
} }
/**
* 解析用户(含存在性校验)
*/
private DbDiyUserEntity resolveUser(String namespace) {
DbDiyUserEntity user = diyUserService.getByNamespace(namespace);
if (user == null) {
throw new ServiceException("用户信息不存在");
}
return user;
}
/**
* 构建商品信息 VO(不含 productList,避免循环引用)
*/
private CustomProductInfoSnakeVO buildProductInfoVO(CustomProductInfoEntity entity) {
CustomProductInfoSnakeVO vo = BeanMapper.snakeCase().convert(entity, CustomProductInfoSnakeVO.class);
if (StringUtils.hasText(vo.getColor_images())) {
vo.setColorImageList(Arrays.asList(vo.getColor_images().split(",")));
}
vo.setProductList(null);
return vo;
}
} }
package com.jomalls.custom.app.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 模板绑定详情 VO
* <p>
* 对齐 TS bindDetail 返回结构:{@code { productInfo, productTemplateAssList }}。
*
* @author Lizh
* @date 2026-06-17
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "模板绑定详情")
public class BindDetailVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "绑定的商品信息")
private CustomProductInfoSnakeVO productInfo;
@Schema(description = "模板明细与商品明细的关联列表")
private List<ProductTemplateAssSnakeVO> productTemplateAssList;
}
...@@ -10,6 +10,7 @@ import java.io.Serial; ...@@ -10,6 +10,7 @@ import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import java.util.List;
/** /**
* Model * Model
...@@ -212,4 +213,16 @@ public class CustomProductItemSnakeVO implements Serializable { ...@@ -212,4 +213,16 @@ public class CustomProductItemSnakeVO implements Serializable {
@Schema(description = "创建时间") @Schema(description = "创建时间")
private Date create_time; private Date create_time;
/**
* 关联商品信息(仅 getBySkus 接口填充,对齐 TS include CustomProductInfo)
*/
@Schema(description = "关联商品信息")
private CustomProductInfoSnakeVO customProductInfo;
/**
* 工厂价格列表(仅 getBySkus 接口填充,对齐 TS include CustomProductFactoryPriceRel)
*/
@Schema(description = "工厂价格列表")
private List<CustomProductFactoryPriceRelSnakeVO> factoryPriceList;
} }
package com.jomalls.custom.app.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
* 模板-商品明细关联条目 VO
* <p>
* 对应 TS bindDetail 返回的 productTemplateAssList 中的每一项。
*
* @author Lizh
* @date 2026-06-17
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "模板-商品明细关联条目")
public class ProductTemplateAssSnakeVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "模板明细 ID")
private Integer template_item_id;
@Schema(description = "模板明细 SKU")
private String template_item_sku;
@Schema(description = "模板明细图片")
private String template_item_image;
@Schema(description = "商品明细 ID(仅绑定时有值)")
private Integer product_item_id;
@Schema(description = "商品明细 SKU(仅绑定时有值)")
private String product_item_sku;
@Schema(description = "商品明细图片(仅绑定时有值)")
private String product_item_image;
}
package com.jomalls.custom.app.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
* 产品模板属性关联 VO(snake_case 命名)
*
* @author Lizh
* @date 2026-06-17
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "产品模板属性关联")
public class ProductTemplateInfoPropertySnakeVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "主键")
private Integer id;
@Schema(description = "模板信息 ID")
private Integer info_id;
@Schema(description = "属性类 ID")
private Integer property_id;
@Schema(description = "属性值 ID")
private Integer value_id;
@Schema(description = "是否为 SKU 属性 0=普通 1=SKU")
private Integer sku_property;
}
package com.jomalls.custom.app.vo;
import com.jomalls.custom.integrate.model.PropertyModel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* 产品模板信息完整 VO(snake_case 命名)
* <p>
* 对齐 TS 项目 {@code ProductTemplateInfo} 返回结构,包含主表字段及所有关联子表数据。
*
* @author Lizh
* @date 2026-06-17
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "产品模板信息完整数据")
public class ProductTemplateInfoSnakeVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
// ==================== 主表字段 ====================
@Schema(description = "主键")
private Integer id;
@Schema(description = "SKU")
private String sku;
@Schema(description = "绑定的商品 ID")
private Integer product_id;
@Schema(description = "绑定的商品 SKU")
private String product_sku;
@Schema(description = "模板 ID(db_diy 表)")
private Integer diy_id;
@Schema(description = "商品名称")
private String name;
@Schema(description = "商品标题")
private String title;
@Schema(description = "商品类别 ID")
private Integer category_id;
@Schema(description = "风格 ID")
private Integer style_id;
@Schema(description = "采购价")
private BigDecimal cost_price;
@Schema(description = "采购价最大值")
private BigDecimal cost_price_max;
@Schema(description = "销售价")
private BigDecimal sales_price;
@Schema(description = "销售价最大值")
private BigDecimal sales_price_max;
@Schema(description = "属性分类 ID1")
private Integer property1_cate_id;
@Schema(description = "属性分类 ID2")
private Integer property2_cate_id;
@Schema(description = "属性分类 ID3")
private Integer property3_cate_id;
@Schema(description = "属性英文名1")
private String property1_enname;
@Schema(description = "属性英文名2")
private String property2_enname;
@Schema(description = "属性英文名3")
private String property3_enname;
@Schema(description = "颜色图")
private String color_images;
@Schema(description = "材质")
private String material;
@Schema(description = "印花类型 0满印 1局部印")
private Integer print_type;
@Schema(description = "创建时间")
private Date create_time;
@Schema(description = "更新时间")
private Date update_time;
// ==================== 计算字段(对应 TS VIRTUAL 字段) ====================
@Schema(description = "颜色图片列表(由 color_images 逗号分割)")
private List<String> colorImageList;
@Schema(description = "备注文本(取自 productRemark.remark)")
private String remark;
// ==================== 关联子表 ====================
@Schema(description = "模板明细列表")
private List<ProductTemplateItemSnakeVO> productList;
@Schema(description = "模板备注")
private ProductTemplateRemarkSnakeVO productRemark;
@Schema(description = "模板属性关联列表(原始数据)")
private List<ProductTemplateInfoPropertySnakeVO> properties;
@Schema(description = "SKU 属性列表(已解析,含属性名和属性值)")
private List<PropertyModel> skuProperties;
@Schema(description = "普通属性列表(已解析,含属性名和属性值)")
private List<PropertyModel> normalProperties;
@Schema(description = "尺码规格列表(仅局部印时有值,去重后)")
private List<ProductTemplateItemSpecSnakeVO> specList;
}
package com.jomalls.custom.app.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 产品模板明细 VO(snake_case 命名)
*
* @author Lizh
* @date 2026-06-17
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "产品模板明细")
public class ProductTemplateItemSnakeVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "主键")
private Integer id;
@Schema(description = "模板 ID")
private Integer template_id;
@Schema(description = "SKU")
private String sku;
@Schema(description = "SKU 商品名称")
private String sku_name;
@Schema(description = "封面图")
private String image;
@Schema(description = "图片集")
private String image_ary;
@Schema(description = "效果图 ID")
private Integer xgt_id;
@Schema(description = "属性分类 ID1")
private Integer property_cate_id1;
@Schema(description = "属性分类 ID2")
private Integer property_cate_id2;
@Schema(description = "属性分类 ID3")
private Integer property_cate_id3;
@Schema(description = "属性 ID1")
private Integer property1_id;
@Schema(description = "属性 ID2")
private Integer property2_id;
@Schema(description = "属性 ID3")
private Integer property3_id;
@Schema(description = "属性编码1")
private String property_code1;
@Schema(description = "属性编码2")
private String property_code2;
@Schema(description = "属性编码3")
private String property_code3;
@Schema(description = "属性名称1")
private String option_enname1;
@Schema(description = "属性名称2")
private String option_enname2;
@Schema(description = "属性名称3")
private String option_enname3;
@Schema(description = "自定义值1")
private String custom_value1;
@Schema(description = "自定义值2")
private String custom_value2;
@Schema(description = "自定义值3")
private String custom_value3;
@Schema(description = "采购价")
private BigDecimal cost_price;
@Schema(description = "销售价")
private BigDecimal sales_price;
@Schema(description = "印花类型 0满印 1局部印")
private Integer print_type;
@Schema(description = "排序")
private Integer sort;
@Schema(description = "关联生产文件 IDS")
private String relation_ids;
@Schema(description = "关联生产文件")
private String relation;
@Schema(description = "custom_product_item 表 ID")
private Integer item_id;
@Schema(description = "custom_product_item 表 SKU")
private String item_sku;
@Schema(description = "货号")
private String catalog_number;
@Schema(description = "稿件宽度")
private Integer mss_width;
@Schema(description = "稿件高度")
private Integer mss_height;
@Schema(description = "尺码类型 1正常码 2大码")
private Integer size_type;
@Schema(description = "创建时间")
private Date create_time;
@Schema(description = "更新时间")
private Date update_time;
}
package com.jomalls.custom.app.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
* 产品模板明细规格 VO(snake_case 命名)
*
* @author Lizh
* @date 2026-06-17
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "产品模板明细规格")
public class ProductTemplateItemSpecSnakeVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "面 ID")
private Integer face_id;
@Schema(description = "面标题")
private String face_title;
@Schema(description = "稿件宽度")
private Integer mss_width;
@Schema(description = "稿件高度")
private Integer mss_height;
@Schema(description = "尺码")
private String size;
@Schema(description = "排序")
private Integer sort;
}
package com.jomalls.custom.app.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 产品模板备注 VO(snake_case 命名)
*
* @author Lizh
* @date 2026-06-17
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "产品模板备注")
public class ProductTemplateRemarkSnakeVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "主键")
private Integer id;
@Schema(description = "模板 ID")
private Integer template_id;
@Schema(description = "备注内容")
private String remark;
@Schema(description = "创建时间")
private Date create_time;
}
package com.jomalls.custom.dal.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 产品模板属性关联实体
* <p>
* 对齐 TS 项目 {@code ProductTemplateInfoProperty} 实体(product_template_info_property 表)。
* 存储模板关联的属性 ID 和属性值 ID,区分 SKU 属性和普通属性。
*
* @author Lizh
* @date 2026-06-17
*/
@Data
@TableName("product_template_info_property")
public class ProductTemplateInfoPropertyEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/** 主键 */
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/** product_template_info 表 ID */
@TableField("info_id")
private Integer infoId;
/** 属性类 ID(关联 base_property 表) */
@TableField("property_id")
private Integer propertyId;
/** 属性值 ID */
@TableField("value_id")
private Integer valueId;
/** 是否为 SKU 属性(0=普通属性, 1=SKU 属性) */
@TableField("sku_property")
private Integer skuProperty;
}
package com.jomalls.custom.dal.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 产品模板明细规格实体
* <p>
* 对齐 TS 项目 {@code ProductTemplateItemSpec} 实体(product_template_item_spec 表)。
* 仅在局部印(print_type=1)场景下使用,存储模板明细的尺码规格信息。
*
* @author Lizh
* @date 2026-06-17
*/
@Data
@TableName("product_template_item_spec")
public class ProductTemplateItemSpecEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/** 主键 */
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/** product_template_info 表 ID */
@TableField("template_id")
private Integer templateId;
/** product_template_item 表 ID */
@TableField("item_id")
private Integer itemId;
/** SKU */
@TableField("sku")
private String sku;
/** 尺码 */
@TableField("size")
private String size;
/** 面 ID */
@TableField("face_id")
private Integer faceId;
/** 面标题 */
@TableField("face_title")
private String faceTitle;
/** 稿件宽度 */
@TableField("mss_width")
private Integer mssWidth;
/** 稿件高度 */
@TableField("mss_height")
private Integer mssHeight;
/** 排序 */
@TableField("sort")
private Integer sort;
}
package com.jomalls.custom.dal.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 产品模板备注实体
* <p>
* 对齐 TS 项目 {@code ProductTemplateRemark} 实体(product_template_remark 表)。
*
* @author Lizh
* @date 2026-06-17
*/
@Data
@TableName("product_template_remark")
public class ProductTemplateRemarkEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/** 主键 */
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/** product_template_info 表 ID */
@TableField("template_id")
private Integer templateId;
/** 备注内容 */
@TableField("remark")
private String remark;
/** 创建时间 */
@TableField("create_time")
private Date createTime;
}
package com.jomalls.custom.dal.mapper;
import com.jomalls.custom.dal.entity.ProductTemplateInfoPropertyEntity;
import com.jomalls.custom.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* ProductTemplateInfoProperty Mapper
*
* @author Lizh
* @date 2026-06-17
*/
@Mapper
public interface ProductTemplateInfoPropertyMapper extends BaseMapper<ProductTemplateInfoPropertyEntity> {
/**
* 根据模板信息 ID 查询属性列表
*
* @param infoId 模板信息 ID
* @return 属性关联列表
*/
List<ProductTemplateInfoPropertyEntity> selectByInfoId(@Param("infoId") Integer infoId);
}
package com.jomalls.custom.dal.mapper;
import com.jomalls.custom.dal.entity.ProductTemplateItemSpecEntity;
import com.jomalls.custom.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* ProductTemplateItemSpec Mapper
*
* @author Lizh
* @date 2026-06-17
*/
@Mapper
public interface ProductTemplateItemSpecMapper extends BaseMapper<ProductTemplateItemSpecEntity> {
/**
* 根据模板 ID 查询规格列表
*
* @param templateId 模板 ID
* @return 规格列表
*/
List<ProductTemplateItemSpecEntity> selectByTemplateId(@Param("templateId") Integer templateId);
}
package com.jomalls.custom.dal.mapper;
import com.jomalls.custom.dal.entity.ProductTemplateRemarkEntity;
import com.jomalls.custom.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* ProductTemplateRemark Mapper
*
* @author Lizh
* @date 2026-06-17
*/
@Mapper
public interface ProductTemplateRemarkMapper extends BaseMapper<ProductTemplateRemarkEntity> {
/**
* 根据模板 ID 查询备注
*
* @param templateId 模板 ID
* @return 备注实体
*/
ProductTemplateRemarkEntity selectByTemplateId(@Param("templateId") Integer templateId);
}
package com.jomalls.custom.domain.service;
import com.jomalls.custom.dal.entity.ProductTemplateInfoPropertyEntity;
import com.jomalls.custom.service.IBaseService;
import java.util.List;
/**
* ProductTemplateInfoProperty 领域服务接口
*
* @author Lizh
* @date 2026-06-17
*/
public interface ProductTemplateInfoPropertyDomainService extends IBaseService<ProductTemplateInfoPropertyEntity> {
/**
* 根据模板信息 ID 查询属性列表
*
* @param infoId 模板信息 ID
* @return 属性关联列表
*/
List<ProductTemplateInfoPropertyEntity> selectByInfoId(Integer infoId);
}
package com.jomalls.custom.domain.service;
import com.jomalls.custom.dal.entity.ProductTemplateItemSpecEntity;
import com.jomalls.custom.service.IBaseService;
import java.util.List;
/**
* ProductTemplateItemSpec 领域服务接口
*
* @author Lizh
* @date 2026-06-17
*/
public interface ProductTemplateItemSpecDomainService extends IBaseService<ProductTemplateItemSpecEntity> {
/**
* 根据模板 ID 查询规格列表
*
* @param templateId 模板 ID
* @return 规格列表
*/
List<ProductTemplateItemSpecEntity> selectByTemplateId(Integer templateId);
}
package com.jomalls.custom.domain.service;
import com.jomalls.custom.dal.entity.ProductTemplateRemarkEntity;
import com.jomalls.custom.service.IBaseService;
/**
* ProductTemplateRemark 领域服务接口
*
* @author Lizh
* @date 2026-06-17
*/
public interface ProductTemplateRemarkDomainService extends IBaseService<ProductTemplateRemarkEntity> {
/**
* 根据模板 ID 查询备注
*
* @param templateId 模板 ID
* @return 备注实体
*/
ProductTemplateRemarkEntity selectByTemplateId(Integer templateId);
}
package com.jomalls.custom.domain.service.impl;
import com.jomalls.custom.dal.entity.ProductTemplateInfoPropertyEntity;
import com.jomalls.custom.dal.mapper.ProductTemplateInfoPropertyMapper;
import com.jomalls.custom.domain.service.ProductTemplateInfoPropertyDomainService;
import com.jomalls.custom.service.impl.BaseServiceImpl;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* ProductTemplateInfoProperty 领域服务实现
*
* @author Lizh
* @date 2026-06-17
*/
@Service
public class ProductTemplateInfoPropertyDomainServiceImpl extends BaseServiceImpl<ProductTemplateInfoPropertyMapper, ProductTemplateInfoPropertyEntity> implements ProductTemplateInfoPropertyDomainService {
@Autowired
public ProductTemplateInfoPropertyDomainServiceImpl(SqlSessionFactory sqlSessionFactory) {
super(sqlSessionFactory);
}
@Override
public List<ProductTemplateInfoPropertyEntity> selectByInfoId(Integer infoId) {
return baseMapper.selectByInfoId(infoId);
}
}
package com.jomalls.custom.domain.service.impl;
import com.jomalls.custom.dal.entity.ProductTemplateItemSpecEntity;
import com.jomalls.custom.dal.mapper.ProductTemplateItemSpecMapper;
import com.jomalls.custom.domain.service.ProductTemplateItemSpecDomainService;
import com.jomalls.custom.service.impl.BaseServiceImpl;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* ProductTemplateItemSpec 领域服务实现
*
* @author Lizh
* @date 2026-06-17
*/
@Service
public class ProductTemplateItemSpecDomainServiceImpl extends BaseServiceImpl<ProductTemplateItemSpecMapper, ProductTemplateItemSpecEntity> implements ProductTemplateItemSpecDomainService {
@Autowired
public ProductTemplateItemSpecDomainServiceImpl(SqlSessionFactory sqlSessionFactory) {
super(sqlSessionFactory);
}
@Override
public List<ProductTemplateItemSpecEntity> selectByTemplateId(Integer templateId) {
return baseMapper.selectByTemplateId(templateId);
}
}
package com.jomalls.custom.domain.service.impl;
import com.jomalls.custom.dal.entity.ProductTemplateRemarkEntity;
import com.jomalls.custom.dal.mapper.ProductTemplateRemarkMapper;
import com.jomalls.custom.domain.service.ProductTemplateRemarkDomainService;
import com.jomalls.custom.service.impl.BaseServiceImpl;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* ProductTemplateRemark 领域服务实现
*
* @author Lizh
* @date 2026-06-17
*/
@Service
public class ProductTemplateRemarkDomainServiceImpl extends BaseServiceImpl<ProductTemplateRemarkMapper, ProductTemplateRemarkEntity> implements ProductTemplateRemarkDomainService {
@Autowired
public ProductTemplateRemarkDomainServiceImpl(SqlSessionFactory sqlSessionFactory) {
super(sqlSessionFactory);
}
@Override
public ProductTemplateRemarkEntity selectByTemplateId(Integer templateId) {
return baseMapper.selectByTemplateId(templateId);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jomalls.custom.dal.mapper.ProductTemplateInfoPropertyMapper">
<resultMap type="com.jomalls.custom.dal.entity.ProductTemplateInfoPropertyEntity" id="productTemplateInfoPropertyMap">
<result property="id" column="id"/>
<result property="infoId" column="info_id"/>
<result property="propertyId" column="property_id"/>
<result property="valueId" column="value_id"/>
<result property="skuProperty" column="sku_property"/>
</resultMap>
<sql id="tableColumns">
id, info_id, property_id, value_id, sku_property
</sql>
<!-- 根据模板信息 ID 查询属性列表 -->
<select id="selectByInfoId" resultMap="productTemplateInfoPropertyMap">
SELECT <include refid="tableColumns"/>
FROM product_template_info_property
WHERE info_id = #{infoId}
</select>
<!-- 批量插入 -->
<insert id="insertBatchSomeColumn">
INSERT INTO product_template_info_property (info_id, property_id, value_id, sku_property) VALUES
<foreach collection="list" item="item" separator=",">
(#{item.infoId}, #{item.propertyId}, #{item.valueId}, #{item.skuProperty})
</foreach>
</insert>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jomalls.custom.dal.mapper.ProductTemplateItemSpecMapper">
<resultMap type="com.jomalls.custom.dal.entity.ProductTemplateItemSpecEntity" id="productTemplateItemSpecMap">
<result property="id" column="id"/>
<result property="templateId" column="template_id"/>
<result property="itemId" column="item_id"/>
<result property="sku" column="sku"/>
<result property="size" column="size"/>
<result property="faceId" column="face_id"/>
<result property="faceTitle" column="face_title"/>
<result property="mssWidth" column="mss_width"/>
<result property="mssHeight" column="mss_height"/>
<result property="sort" column="sort"/>
</resultMap>
<sql id="tableColumns">
id, template_id, item_id, sku, size, face_id, face_title, mss_width, mss_height, sort
</sql>
<!-- 根据模板 ID 查询规格列表 -->
<select id="selectByTemplateId" resultMap="productTemplateItemSpecMap">
SELECT <include refid="tableColumns"/>
FROM product_template_item_spec
WHERE template_id = #{templateId}
</select>
<!-- 批量插入 -->
<insert id="insertBatchSomeColumn">
INSERT INTO product_template_item_spec (template_id, item_id, sku, size, face_id, face_title, mss_width, mss_height, sort) VALUES
<foreach collection="list" item="item" separator=",">
(#{item.templateId}, #{item.itemId}, #{item.sku}, #{item.size}, #{item.faceId}, #{item.faceTitle}, #{item.mssWidth}, #{item.mssHeight}, #{item.sort})
</foreach>
</insert>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jomalls.custom.dal.mapper.ProductTemplateRemarkMapper">
<resultMap type="com.jomalls.custom.dal.entity.ProductTemplateRemarkEntity" id="productTemplateRemarkMap">
<result property="id" column="id"/>
<result property="templateId" column="template_id"/>
<result property="remark" column="remark"/>
<result property="createTime" column="create_time"/>
</resultMap>
<sql id="tableColumns">
id, template_id, remark, create_time
</sql>
<!-- 根据模板 ID 查询备注 -->
<select id="selectByTemplateId" resultMap="productTemplateRemarkMap">
SELECT <include refid="tableColumns"/>
FROM product_template_remark
WHERE template_id = #{templateId}
</select>
<!-- 批量插入 -->
<insert id="insertBatchSomeColumn">
INSERT INTO product_template_remark (template_id, remark, create_time) VALUES
<foreach collection="list" item="item" separator=",">
(#{item.templateId}, #{item.remark}, #{item.createTime})
</foreach>
</insert>
</mapper>
package com.jomalls.custom.webapp.controller;
import com.jomalls.custom.app.service.ProductTemplateInfoService;
import com.jomalls.custom.app.vo.BindDetailVO;
import com.jomalls.custom.app.vo.ProductTemplateInfoSnakeVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* 产品模板 Controller
* <p>
* 对齐 TS 项目 {@code ApiProductTemplateInfoController} 的 /get 和 /bindDetail 端点。
*
* @author Lizh
* @date 2026-06-17
*/
@Slf4j
@RestController
@Tag(name = "产品模板管理", description = "产品模板管理接口")
@RequestMapping("/api/v3/product/template")
@RequiredArgsConstructor
public class ProductTemplateInfoController {
private final ProductTemplateInfoService productTemplateInfoService;
@Operation(summary = "根据 ID 或 SKU 获取模板完整数据", description = "并行加载主表及所有关联子表数据,含属性名称解析和规格加载")
@GetMapping("/get")
public ProductTemplateInfoSnakeVO getByIdOrSku(
@Parameter(description = "模板 ID") @RequestParam(required = false) Integer id,
@Parameter(description = "模板 SKU") @RequestParam(required = false) String sku) {
return productTemplateInfoService.getByIdOrSku(id, sku);
}
@Operation(summary = "查看绑定详情", description = "查看模板与商品的绑定详情,返回商品信息及模板-商品明细关联列表")
@GetMapping("/bindDetail")
public BindDetailVO bindDetail(
@Parameter(description = "模板 ID") @RequestParam(required = false) Integer id,
@Parameter(description = "模板 SKU") @RequestParam(required = false) String sku) {
return productTemplateInfoService.bindDetail(id, sku);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment