Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
custom-server
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lizhonghong
custom-server
Commits
05642cf7
Commit
05642cf7
authored
Jun 17, 2026
by
Lizh
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
迁移/api/product/template/get接口
parent
9d8ade8c
Hide whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
1478 additions
and
23 deletions
+1478
-23
.gitignore
+1
-0
custom-server-app/src/main/java/com/jomalls/custom/app/service/ProductTemplateInfoService.java
+35
-0
custom-server-app/src/main/java/com/jomalls/custom/app/service/impl/CustomProductInfoServiceImpl.java
+7
-1
custom-server-app/src/main/java/com/jomalls/custom/app/service/impl/CustomProductItemServiceImpl.java
+86
-22
custom-server-app/src/main/java/com/jomalls/custom/app/service/impl/ProductTemplateInfoServiceImpl.java
+318
-0
custom-server-app/src/main/java/com/jomalls/custom/app/vo/BindDetailVO.java
+36
-0
custom-server-app/src/main/java/com/jomalls/custom/app/vo/CustomProductItemSnakeVO.java
+13
-0
custom-server-app/src/main/java/com/jomalls/custom/app/vo/ProductTemplateAssSnakeVO.java
+47
-0
custom-server-app/src/main/java/com/jomalls/custom/app/vo/ProductTemplateInfoPropertySnakeVO.java
+42
-0
custom-server-app/src/main/java/com/jomalls/custom/app/vo/ProductTemplateInfoSnakeVO.java
+135
-0
custom-server-app/src/main/java/com/jomalls/custom/app/vo/ProductTemplateItemSnakeVO.java
+137
-0
custom-server-app/src/main/java/com/jomalls/custom/app/vo/ProductTemplateItemSpecSnakeVO.java
+45
-0
custom-server-app/src/main/java/com/jomalls/custom/app/vo/ProductTemplateRemarkSnakeVO.java
+40
-0
custom-server-domain/src/main/java/com/jomalls/custom/dal/entity/ProductTemplateInfoPropertyEntity.java
+47
-0
custom-server-domain/src/main/java/com/jomalls/custom/dal/entity/ProductTemplateItemSpecEntity.java
+67
-0
custom-server-domain/src/main/java/com/jomalls/custom/dal/entity/ProductTemplateRemarkEntity.java
+43
-0
custom-server-domain/src/main/java/com/jomalls/custom/dal/mapper/ProductTemplateInfoPropertyMapper.java
+26
-0
custom-server-domain/src/main/java/com/jomalls/custom/dal/mapper/ProductTemplateItemSpecMapper.java
+26
-0
custom-server-domain/src/main/java/com/jomalls/custom/dal/mapper/ProductTemplateRemarkMapper.java
+24
-0
custom-server-domain/src/main/java/com/jomalls/custom/domain/service/ProductTemplateInfoPropertyDomainService.java
+23
-0
custom-server-domain/src/main/java/com/jomalls/custom/domain/service/ProductTemplateItemSpecDomainService.java
+23
-0
custom-server-domain/src/main/java/com/jomalls/custom/domain/service/ProductTemplateRemarkDomainService.java
+21
-0
custom-server-domain/src/main/java/com/jomalls/custom/domain/service/impl/ProductTemplateInfoPropertyDomainServiceImpl.java
+31
-0
custom-server-domain/src/main/java/com/jomalls/custom/domain/service/impl/ProductTemplateItemSpecDomainServiceImpl.java
+31
-0
custom-server-domain/src/main/java/com/jomalls/custom/domain/service/impl/ProductTemplateRemarkDomainServiceImpl.java
+29
-0
custom-server-domain/src/main/resources/mapper/ProductTemplateInfoPropertyMapper.xml
+31
-0
custom-server-domain/src/main/resources/mapper/ProductTemplateItemSpecMapper.xml
+36
-0
custom-server-domain/src/main/resources/mapper/ProductTemplateRemarkMapper.xml
+30
-0
custom-server-webapp/src/main/java/com/jomalls/custom/webapp/controller/ProductTemplateInfoController.java
+48
-0
No files found.
.gitignore
View file @
05642cf7
...
...
@@ -15,4 +15,5 @@
.claude/
CLAUDE.md
docs
plans
custom-server-app/src/main/java/com/jomalls/custom/app/service/ProductTemplateInfoService.java
0 → 100644
View file @
05642cf7
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
);
}
custom-server-app/src/main/java/com/jomalls/custom/app/service/impl/CustomProductInfoServiceImpl.java
View file @
05642cf7
...
...
@@ -410,7 +410,13 @@ public class CustomProductInfoServiceImpl implements CustomProductInfoService {
CustomProductInfoEntity
entity
=
validateAndQueryEntity
(
id
,
sku
);
final
Integer
productId
=
entity
.
getId
();
// 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. 并行查询所有子表数据
ProductRelatedData
relatedData
=
queryRelatedDataInParallel
(
productId
);
// 4. 组合完整 VO
...
...
custom-server-app/src/main/java/com/jomalls/custom/app/service/impl/CustomProductItemServiceImpl.java
View file @
05642cf7
...
...
@@ -5,10 +5,13 @@ import com.jomalls.custom.app.exception.ServiceException;
import
com.jomalls.custom.app.service.CustomProductItemService
;
import
com.jomalls.custom.app.service.DiyUserService
;
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.dal.entity.*
;
import
com.jomalls.custom.domain.service.*
;
import
com.jomalls.custom.security.SecurityUtils
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
...
...
@@ -41,6 +44,7 @@ public class CustomProductItemServiceImpl implements CustomProductItemService {
private
final
LogCustomProductDomainService
logCustomProductDomainService
;
private
final
LogProductTemplateDomainService
logProductTemplateDomainService
;
private
final
DiyUserService
diyUserService
;
private
final
CustomProductFactoryPriceRelDomainService
customProductFactoryPriceRelDomainService
;
private
final
TransactionTemplate
transactionTemplate
;
...
...
@@ -228,40 +232,77 @@ public class CustomProductItemServiceImpl implements CustomProductItemService {
throw
new
ServiceException
(
"SKU不能为空"
);
}
// ① 查询明细(含关联商品信息的工厂字段)(对齐 TS:152-15
7
)
// ① 查询明细(含关联商品信息的工厂字段)(对齐 TS:152-15
3 include CustomProductInfo
)
List
<
CustomProductItemEntity
>
items
=
customProductItemDomainService
.
selectBySkusWithInfo
(
skus
);
if
(
CollectionUtils
.
isEmpty
(
items
))
{
return
Collections
.
emptyList
();
}
// ② 如果传了 namespace,查询用户并应用折扣(对齐 TS:165-174)
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
();
}
// ③ 转换实体为响应 VO,附加工厂信息和 print_type(对齐 TS:158-164)
// 工厂价格 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
();
}
// ③ 如果传了 namespace,查询用户(对齐 TS:165-168)
final
DbDiyUserEntity
user
=
StringUtils
.
hasText
(
namespace
)
?
resolveUser
(
namespace
)
:
null
;
// ④ 转换实体为响应 VO(对齐 TS:158-164 + include 关联数据)
return
items
.
stream
().
map
(
item
->
{
CustomProductItemSnakeVO
vo
=
BeanMapper
.
snakeCase
().
convert
(
item
,
CustomProductItemSnakeVO
.
class
);
// 附加工厂信息(来自 JOIN custom_product_info)
vo
.
setFactory_id
(
item
.
getInfoFactoryId
());
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
)
{
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
;
}).
collect
(
Collectors
.
toList
());
}
...
...
@@ -291,4 +332,27 @@ public class CustomProductItemServiceImpl implements CustomProductItemService {
log
.
setCreateTime
(
new
Date
());
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
;
}
}
custom-server-app/src/main/java/com/jomalls/custom/app/service/impl/ProductTemplateInfoServiceImpl.java
0 → 100644
View file @
05642cf7
package
com
.
jomalls
.
custom
.
app
.
service
.
impl
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.jomalls.custom.app.exception.ServiceException
;
import
com.jomalls.custom.app.service.ProductTemplateInfoService
;
import
com.jomalls.custom.app.utils.BeanMapper
;
import
com.jomalls.custom.app.utils.CustomAsserts
;
import
com.jomalls.custom.app.vo.*
;
import
com.jomalls.custom.dal.entity.*
;
import
com.jomalls.custom.domain.service.*
;
import
com.jomalls.custom.integrate.model.PropertyModel
;
import
com.jomalls.custom.integrate.model.PropertyValueModel
;
import
com.jomalls.custom.integrate.service.SaasAdminService
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.stereotype.Service
;
import
java.util.*
;
import
java.util.concurrent.CompletableFuture
;
import
java.util.concurrent.ThreadPoolExecutor
;
import
java.util.concurrent.TimeUnit
;
import
java.util.stream.Collectors
;
/**
* 产品模板信息服务实现
* <p>
* 对齐 TS 项目 {@code ProductTemplateInfoService} 的 getByIdOrSku 和 bindDetail 方法。
* 使用 CompletableFuture 并行查询关联子表,通过 BasePropertyClient 解析属性名称。
*
* @author Lizh
* @date 2026-06-17
*/
@Slf4j
@Service
@RequiredArgsConstructor
public
class
ProductTemplateInfoServiceImpl
implements
ProductTemplateInfoService
{
/** 并行查询超时时间(秒) */
private
static
final
long
QUERY_TIMEOUT_SECONDS
=
30
;
private
final
ProductTemplateInfoDomainService
productTemplateInfoDomainService
;
private
final
ProductTemplateItemDomainService
productTemplateItemDomainService
;
private
final
ProductTemplateRemarkDomainService
productTemplateRemarkDomainService
;
private
final
ProductTemplateInfoPropertyDomainService
productTemplateInfoPropertyDomainService
;
private
final
ProductTemplateItemSpecDomainService
productTemplateItemSpecDomainService
;
private
final
CustomProductInfoDomainService
customProductInfoDomainService
;
private
final
CustomProductItemDomainService
customProductItemDomainService
;
private
final
SaasAdminService
saasAdminService
;
private
final
ThreadPoolExecutor
threadPoolExecutor
;
// ==================== getByIdOrSku ====================
@Override
public
ProductTemplateInfoSnakeVO
getByIdOrSku
(
Integer
id
,
String
sku
)
{
// 1. 校验参数并查询主实体
ProductTemplateInfoEntity
entity
=
validateAndQueryEntity
(
id
,
sku
);
CustomAsserts
.
nonNull
(
entity
,
"未查询到关联的信息模板"
);
final
Integer
templateId
=
entity
.
getId
();
// 2. 并行查询关联子表
CompletableFuture
<
List
<
ProductTemplateItemEntity
>>
itemsFuture
=
CompletableFuture
.
supplyAsync
(()
->
productTemplateItemDomainService
.
selectByTemplateId
(
templateId
),
threadPoolExecutor
);
CompletableFuture
<
ProductTemplateRemarkEntity
>
remarkFuture
=
CompletableFuture
.
supplyAsync
(()
->
productTemplateRemarkDomainService
.
selectByTemplateId
(
templateId
),
threadPoolExecutor
);
CompletableFuture
<
List
<
ProductTemplateInfoPropertyEntity
>>
propertiesFuture
=
CompletableFuture
.
supplyAsync
(()
->
productTemplateInfoPropertyDomainService
.
selectByInfoId
(
templateId
),
threadPoolExecutor
);
CompletableFuture
<
List
<
ProductTemplateItemSpecEntity
>>
specsFuture
=
CompletableFuture
.
supplyAsync
(()
->
{
// 仅局部印时查询规格
if
(
entity
.
getPrintType
()
!=
null
&&
entity
.
getPrintType
()
==
1
)
{
return
productTemplateItemSpecDomainService
.
selectByTemplateId
(
templateId
);
}
return
Collections
.<
ProductTemplateItemSpecEntity
>
emptyList
();
},
threadPoolExecutor
);
// 3. 等待所有并行查询完成
CompletableFuture
.
allOf
(
itemsFuture
,
remarkFuture
,
propertiesFuture
,
specsFuture
)
.
orTimeout
(
QUERY_TIMEOUT_SECONDS
,
TimeUnit
.
SECONDS
)
.
join
();
List
<
ProductTemplateItemEntity
>
items
=
itemsFuture
.
join
();
ProductTemplateRemarkEntity
remark
=
remarkFuture
.
join
();
List
<
ProductTemplateInfoPropertyEntity
>
properties
=
propertiesFuture
.
join
();
List
<
ProductTemplateItemSpecEntity
>
specs
=
specsFuture
.
join
();
// 4. Items 按 sort 排序
if
(
items
!=
null
)
{
items
.
sort
(
Comparator
.
comparing
(
ProductTemplateItemEntity:
:
getSort
,
Comparator
.
nullsLast
(
Comparator
.
naturalOrder
())));
}
// 5. 组装主 VO
ProductTemplateInfoSnakeVO
vo
=
BeanMapper
.
snakeCase
().
convert
(
entity
,
ProductTemplateInfoSnakeVO
.
class
);
// 6. 计算字段
// colorImageList: 由 color_images 逗号分割
if
(
StringUtils
.
isNotBlank
(
entity
.
getColorImages
()))
{
vo
.
setColorImageList
(
Arrays
.
asList
(
entity
.
getColorImages
().
split
(
","
)));
}
else
{
vo
.
setColorImageList
(
Collections
.
emptyList
());
}
// remark: 取自 productRemark.remark
if
(
remark
!=
null
)
{
vo
.
setRemark
(
remark
.
getRemark
());
vo
.
setProductRemark
(
BeanMapper
.
snakeCase
().
convert
(
remark
,
ProductTemplateRemarkSnakeVO
.
class
));
}
// 7. 转换关联数据
if
(
items
!=
null
)
{
vo
.
setProductList
(
BeanMapper
.
snakeCase
().
convertList
(
items
,
ProductTemplateItemSnakeVO
.
class
));
}
if
(
properties
!=
null
)
{
vo
.
setProperties
(
BeanMapper
.
snakeCase
().
convertList
(
properties
,
ProductTemplateInfoPropertySnakeVO
.
class
));
}
// 8. 解析属性名称(调用 baseProperty API)
resolveProperties
(
properties
,
vo
);
// 9. 规格去重(按 face_id + "_" + size)
if
(
specs
!=
null
&&
!
specs
.
isEmpty
())
{
vo
.
setSpecList
(
buildSpecList
(
specs
));
}
return
vo
;
}
// ==================== bindDetail ====================
@Override
public
BindDetailVO
bindDetail
(
Integer
id
,
String
sku
)
{
// 1. 校验参数并查询主实体
ProductTemplateInfoEntity
entity
=
validateAndQueryEntity
(
id
,
sku
);
CustomAsserts
.
nonNull
(
entity
,
"信息模板不存在"
);
// 2. 验证模板已绑定商品
if
(
entity
.
getProductId
()
==
null
)
{
throw
new
ServiceException
(
"未绑定商品"
);
}
final
Integer
productId
=
entity
.
getProductId
();
// 3. 并行查询模板明细和绑定商品
CompletableFuture
<
List
<
ProductTemplateItemEntity
>>
templateItemsFuture
=
CompletableFuture
.
supplyAsync
(()
->
productTemplateItemDomainService
.
selectByTemplateId
(
entity
.
getId
()),
threadPoolExecutor
);
CompletableFuture
<
CustomProductInfoEntity
>
productInfoFuture
=
CompletableFuture
.
supplyAsync
(()
->
customProductInfoDomainService
.
getById
(
productId
),
threadPoolExecutor
);
CompletableFuture
<
List
<
CustomProductItemEntity
>>
productItemsFuture
=
CompletableFuture
.
supplyAsync
(()
->
customProductItemDomainService
.
selectByProductId
(
productId
),
threadPoolExecutor
);
CompletableFuture
.
allOf
(
templateItemsFuture
,
productInfoFuture
,
productItemsFuture
)
.
orTimeout
(
QUERY_TIMEOUT_SECONDS
,
TimeUnit
.
SECONDS
)
.
join
();
List
<
ProductTemplateItemEntity
>
templateItems
=
templateItemsFuture
.
join
();
CustomProductInfoEntity
productInfo
=
productInfoFuture
.
join
();
List
<
CustomProductItemEntity
>
productItems
=
productItemsFuture
.
join
();
// 4. 验证绑定商品存在
CustomAsserts
.
nonNull
(
productInfo
,
"绑定商品信息不存在"
);
// 5. 构建商品明细 Map(key = id)
Map
<
Integer
,
CustomProductItemEntity
>
productItemMap
;
if
(
productItems
!=
null
&&
!
productItems
.
isEmpty
())
{
productItemMap
=
productItems
.
stream
()
.
collect
(
Collectors
.
toMap
(
CustomProductItemEntity:
:
getId
,
item
->
item
,
(
a
,
b
)
->
a
));
}
else
{
productItemMap
=
Collections
.
emptyMap
();
}
// 6. 模板明细按 sort 排序
if
(
templateItems
!=
null
)
{
templateItems
.
sort
(
Comparator
.
comparing
(
ProductTemplateItemEntity:
:
getSort
,
Comparator
.
nullsLast
(
Comparator
.
naturalOrder
())));
}
// 7. 构建关联列表
List
<
ProductTemplateAssSnakeVO
>
assList
=
new
ArrayList
<>();
if
(
templateItems
!=
null
)
{
for
(
ProductTemplateItemEntity
templateItem
:
templateItems
)
{
ProductTemplateAssSnakeVO
assVO
=
ProductTemplateAssSnakeVO
.
builder
()
.
template_item_id
(
templateItem
.
getId
())
.
template_item_sku
(
templateItem
.
getSku
())
.
template_item_image
(
templateItem
.
getImage
())
.
build
();
// 匹配商品明细
if
(
templateItem
.
getItemId
()
!=
null
)
{
CustomProductItemEntity
productItem
=
productItemMap
.
get
(
templateItem
.
getItemId
());
if
(
productItem
!=
null
)
{
assVO
.
setProduct_item_id
(
productItem
.
getId
());
assVO
.
setProduct_item_sku
(
productItem
.
getSku
());
assVO
.
setProduct_item_image
(
productItem
.
getImage
());
}
}
assList
.
add
(
assVO
);
}
}
// 8. 转换商品信息 VO(不包含 productList,对齐 TS:customProductInfo.productList = null)
CustomProductInfoSnakeVO
productInfoVO
=
BeanMapper
.
snakeCase
().
convert
(
productInfo
,
CustomProductInfoSnakeVO
.
class
);
productInfoVO
.
setProductList
(
null
);
return
BindDetailVO
.
builder
()
.
productInfo
(
productInfoVO
)
.
productTemplateAssList
(
assList
)
.
build
();
}
// ==================== 私有方法 ====================
/**
* 校验 id/sku 参数并查询主实体
*
* @param id 模板 ID(可选)
* @param sku 模板 SKU(可选)
* @return 模板实体,未找到返回 null
*/
private
ProductTemplateInfoEntity
validateAndQueryEntity
(
Integer
id
,
String
sku
)
{
if
(
id
!=
null
)
{
return
productTemplateInfoDomainService
.
getById
(
id
);
}
if
(
StringUtils
.
isNotBlank
(
sku
))
{
return
productTemplateInfoDomainService
.
getOne
(
new
LambdaQueryWrapper
<
ProductTemplateInfoEntity
>()
.
eq
(
ProductTemplateInfoEntity:
:
getSku
,
sku
));
}
// id 和 sku 均为空
throw
new
ServiceException
(
"模板id和模板SKU均不能同时为空"
);
}
/**
* 解析属性名称
* <p>
* 调用 baseProperty API 获取属性详情,过滤属性值列表,
* 然后拆分为 skuProperties 和 normalProperties。
*
* @param properties 原始属性关联列表
* @param vo 目标 VO(结果写入 skuProperties / normalProperties)
*/
private
void
resolveProperties
(
List
<
ProductTemplateInfoPropertyEntity
>
properties
,
ProductTemplateInfoSnakeVO
vo
)
{
if
(
properties
==
null
||
properties
.
isEmpty
())
{
vo
.
setSkuProperties
(
Collections
.
emptyList
());
vo
.
setNormalProperties
(
Collections
.
emptyList
());
return
;
}
// 收集所有 property_id,逗号拼接
String
propIds
=
properties
.
stream
()
.
map
(
ProductTemplateInfoPropertyEntity:
:
getPropertyId
)
.
filter
(
Objects:
:
nonNull
)
.
map
(
String:
:
valueOf
)
.
distinct
()
.
collect
(
Collectors
.
joining
(
","
));
if
(
propIds
.
isEmpty
())
{
vo
.
setSkuProperties
(
Collections
.
emptyList
());
vo
.
setNormalProperties
(
Collections
.
emptyList
());
return
;
}
// 调用 baseProperty API 获取属性详情(复用 SaasAdminService)
List
<
PropertyModel
>
allProperties
=
saasAdminService
.
getPropertyByIds
(
propIds
);
if
(
allProperties
==
null
||
allProperties
.
isEmpty
())
{
vo
.
setSkuProperties
(
Collections
.
emptyList
());
vo
.
setNormalProperties
(
Collections
.
emptyList
());
return
;
}
// 收集当前模板引用的所有 value_id
Set
<
Integer
>
valueIds
=
properties
.
stream
()
.
map
(
ProductTemplateInfoPropertyEntity:
:
getValueId
)
.
filter
(
Objects:
:
nonNull
)
.
collect
(
Collectors
.
toSet
());
// 过滤每个属性的值列表,只保留引用的值
for
(
PropertyModel
prop
:
allProperties
)
{
if
(
prop
.
getValueList
()
!=
null
&&
!
prop
.
getValueList
().
isEmpty
()
&&
!
valueIds
.
isEmpty
())
{
List
<
PropertyValueModel
>
filteredValues
=
prop
.
getValueList
().
stream
()
.
filter
(
v
->
valueIds
.
contains
(
v
.
getId
()))
.
collect
(
Collectors
.
toList
());
prop
.
setValueList
(
filteredValues
);
}
}
// 拆分为 SKU 属性和普通属性
List
<
PropertyModel
>
skuProperties
=
allProperties
.
stream
()
.
filter
(
p
->
Boolean
.
TRUE
.
equals
(
p
.
getSkuProperty
()))
.
collect
(
Collectors
.
toList
());
List
<
PropertyModel
>
normalProperties
=
allProperties
.
stream
()
.
filter
(
p
->
!
Boolean
.
TRUE
.
equals
(
p
.
getSkuProperty
()))
.
collect
(
Collectors
.
toList
());
vo
.
setSkuProperties
(
skuProperties
);
vo
.
setNormalProperties
(
normalProperties
);
}
/**
* 构建去重并排序的规格列表
* <p>
* 对齐 TS 的 ProductTemplateItemSpecService.list():
* 按 face_id + "_" + size 去重,保留第一条,然后按 sort 排序。
*
* @param specs 原始规格列表
* @return 去重排序后的 VO 列表
*/
private
List
<
ProductTemplateItemSpecSnakeVO
>
buildSpecList
(
List
<
ProductTemplateItemSpecEntity
>
specs
)
{
Map
<
String
,
ProductTemplateItemSpecEntity
>
uniqueMap
=
new
LinkedHashMap
<>();
for
(
ProductTemplateItemSpecEntity
spec
:
specs
)
{
String
key
=
spec
.
getFaceId
()
+
"_"
+
spec
.
getSize
();
uniqueMap
.
putIfAbsent
(
key
,
spec
);
}
return
uniqueMap
.
values
().
stream
()
.
sorted
(
Comparator
.
comparing
(
ProductTemplateItemSpecEntity:
:
getSort
,
Comparator
.
nullsLast
(
Comparator
.
naturalOrder
())))
.
map
(
spec
->
BeanMapper
.
snakeCase
().
convert
(
spec
,
ProductTemplateItemSpecSnakeVO
.
class
))
.
collect
(
Collectors
.
toList
());
}
}
custom-server-app/src/main/java/com/jomalls/custom/app/vo/BindDetailVO.java
0 → 100644
View file @
05642cf7
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
;
}
custom-server-app/src/main/java/com/jomalls/custom/app/vo/CustomProductItemSnakeVO.java
View file @
05642cf7
...
...
@@ -10,6 +10,7 @@ import java.io.Serial;
import
java.io.Serializable
;
import
java.math.BigDecimal
;
import
java.util.Date
;
import
java.util.List
;
/**
* Model
...
...
@@ -212,4 +213,16 @@ public class CustomProductItemSnakeVO implements Serializable {
@Schema
(
description
=
"创建时间"
)
private
Date
create_time
;
/**
* 关联商品信息(仅 getBySkus 接口填充,对齐 TS include CustomProductInfo)
*/
@Schema
(
description
=
"关联商品信息"
)
private
CustomProductInfoSnakeVO
customProductInfo
;
/**
* 工厂价格列表(仅 getBySkus 接口填充,对齐 TS include CustomProductFactoryPriceRel)
*/
@Schema
(
description
=
"工厂价格列表"
)
private
List
<
CustomProductFactoryPriceRelSnakeVO
>
factoryPriceList
;
}
custom-server-app/src/main/java/com/jomalls/custom/app/vo/ProductTemplateAssSnakeVO.java
0 → 100644
View file @
05642cf7
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
;
}
custom-server-app/src/main/java/com/jomalls/custom/app/vo/ProductTemplateInfoPropertySnakeVO.java
0 → 100644
View file @
05642cf7
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
;
}
custom-server-app/src/main/java/com/jomalls/custom/app/vo/ProductTemplateInfoSnakeVO.java
0 → 100644
View file @
05642cf7
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
;
}
custom-server-app/src/main/java/com/jomalls/custom/app/vo/ProductTemplateItemSnakeVO.java
0 → 100644
View file @
05642cf7
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
;
}
custom-server-app/src/main/java/com/jomalls/custom/app/vo/ProductTemplateItemSpecSnakeVO.java
0 → 100644
View file @
05642cf7
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
;
}
custom-server-app/src/main/java/com/jomalls/custom/app/vo/ProductTemplateRemarkSnakeVO.java
0 → 100644
View file @
05642cf7
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
;
}
custom-server-domain/src/main/java/com/jomalls/custom/dal/entity/ProductTemplateInfoPropertyEntity.java
0 → 100644
View file @
05642cf7
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
;
}
custom-server-domain/src/main/java/com/jomalls/custom/dal/entity/ProductTemplateItemSpecEntity.java
0 → 100644
View file @
05642cf7
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
;
}
custom-server-domain/src/main/java/com/jomalls/custom/dal/entity/ProductTemplateRemarkEntity.java
0 → 100644
View file @
05642cf7
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
;
}
custom-server-domain/src/main/java/com/jomalls/custom/dal/mapper/ProductTemplateInfoPropertyMapper.java
0 → 100644
View file @
05642cf7
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
);
}
custom-server-domain/src/main/java/com/jomalls/custom/dal/mapper/ProductTemplateItemSpecMapper.java
0 → 100644
View file @
05642cf7
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
);
}
custom-server-domain/src/main/java/com/jomalls/custom/dal/mapper/ProductTemplateRemarkMapper.java
0 → 100644
View file @
05642cf7
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
);
}
custom-server-domain/src/main/java/com/jomalls/custom/domain/service/ProductTemplateInfoPropertyDomainService.java
0 → 100644
View file @
05642cf7
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
);
}
custom-server-domain/src/main/java/com/jomalls/custom/domain/service/ProductTemplateItemSpecDomainService.java
0 → 100644
View file @
05642cf7
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
);
}
custom-server-domain/src/main/java/com/jomalls/custom/domain/service/ProductTemplateRemarkDomainService.java
0 → 100644
View file @
05642cf7
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
);
}
custom-server-domain/src/main/java/com/jomalls/custom/domain/service/impl/ProductTemplateInfoPropertyDomainServiceImpl.java
0 → 100644
View file @
05642cf7
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
);
}
}
custom-server-domain/src/main/java/com/jomalls/custom/domain/service/impl/ProductTemplateItemSpecDomainServiceImpl.java
0 → 100644
View file @
05642cf7
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
);
}
}
custom-server-domain/src/main/java/com/jomalls/custom/domain/service/impl/ProductTemplateRemarkDomainServiceImpl.java
0 → 100644
View file @
05642cf7
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
);
}
}
custom-server-domain/src/main/resources/mapper/ProductTemplateInfoPropertyMapper.xml
0 → 100644
View file @
05642cf7
<?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>
custom-server-domain/src/main/resources/mapper/ProductTemplateItemSpecMapper.xml
0 → 100644
View file @
05642cf7
<?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>
custom-server-domain/src/main/resources/mapper/ProductTemplateRemarkMapper.xml
0 → 100644
View file @
05642cf7
<?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>
custom-server-webapp/src/main/java/com/jomalls/custom/webapp/controller/ProductTemplateInfoController.java
0 → 100644
View file @
05642cf7
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
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment