feat(REQ-2186): 产品管理相关接口实现

This commit is contained in:
李昆鹏 2024-05-06 18:17:05 +08:00
parent 007e84a31c
commit 992b4a8801
17 changed files with 917 additions and 16 deletions

View File

@ -6,9 +6,9 @@
dev环境启动参数
-Dspring.datasource.url=jdbc:mysql://172.16.2.197:3311/pudge-dev?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=true&verifyServerCertificate=false&rewriteBatchedStatements=true
-Drocketmq.name-server=114.116.202.128:9876
-Drocketmq.name-server=172.16.2.82:9876
-DCUSTOM_ENV=dev
-Dspring.profiles.active=dev
-Dspring.redis.host=123.249.44.111
-Dspring.redis.host=172.16.2.23
-Dspring.redis.port=31270
-Dserver.port=8080

View File

@ -10,6 +10,9 @@ import cn.axzo.tyr.client.model.product.ProductSearchListReq;
import cn.axzo.tyr.client.model.product.ProductSearchPageReq;
import cn.axzo.tyr.client.model.product.ProductUpdateReq;
import cn.axzo.tyr.client.model.product.ProductVO;
import cn.axzo.tyr.client.model.req.ProductSaveReq;
import cn.axzo.tyr.client.model.req.UpdateProductStatusReq;
import cn.axzo.tyr.client.model.res.ChiefTerminalResp;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
@ -113,4 +116,33 @@ public interface ProductApi {
*/
@PostMapping("api/auth/product/feature/query")
ApiResult<Map<Long, List<ProductFeatureRelationVO>>> queryProductFeatureRelationByWorkspace(@RequestBody Set<Long> workspaceIds);
/**
* 产品上下架
*
* @param req 产品id及状态
* @return 是否更新成功
*/
@PostMapping("api/auth/product/updateStatus")
ApiResult<Void> updateStatus(@Validated @RequestBody UpdateProductStatusReq req);
/**
* 保存更新产品v2版本
*
* @param req 产品信息
* @return 返回产品ID
*/
@PostMapping("api/auth/product/saveOrUpdate")
ApiResult<Long> saveOrUpdate(@Validated @RequestBody ProductSaveReq req);
/**
* 获取政务端列表
*
* @param terminal 政务端
* @return {@link ChiefTerminalResp}
*/
@GetMapping("api/auth/product/getChiefTerminal")
ApiResult<List<ChiefTerminalResp>> getChiefTerminal(@RequestParam @NotNull(message = "terminal不能为空") String terminal);
}

View File

@ -0,0 +1,60 @@
package cn.axzo.tyr.client.model.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.Optional;
/**
* @author likunpeng
* @version 1.0
* @date 2024/5/6
*/
@Getter
@AllArgsConstructor
public enum ProductModuleCategoryEnum {
/**
* 产品版本
*/
PRODUCT_VERSION("PRODUCT_VERSION", "产品版本"),
/**
* 增值服务包
*/
ADD_VALUE_SERVICE("ADD_VALUE_SERVICE", "增值服务包"),
/**
* 通用产品
*/
GENERAL_SERVICE("GENERAL_SERVICE", "通用产品"),
/**
* 硬件产品
*/
HARD_WARE("HARD_WARE", "硬件产品"),
;
@EnumValue
@JsonValue
private String code;
private String desc;
/**
* 通过value值获取枚举类型
*
* @param code code值
* @return
*/
public static ProductModuleCategoryEnum getByCode(String code) {
return Arrays.stream(values()).filter(l -> l.getCode().equals(code)).findFirst().orElse(null);
}
public static String getDescByCode(String code) {
return Optional.ofNullable(getByCode(code)).map(ProductModuleCategoryEnum::getDesc).orElse(null);
}
}

View File

@ -0,0 +1,72 @@
package cn.axzo.tyr.client.model.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
/**
* @author likunpeng
* @version 1.0
* @date 2024/5/6
*/
@Getter
@AllArgsConstructor
public enum WorkspaceTypeCodeEnum {
/**
* 企业
*/
GENERAL_ENT("1", "企业"),
/**
* 项目
*/
GENERAL_PROJECT("2", "项目"),
/**
* 政务
*/
CHIEF("3", "政务"),
/**
* 班组
*/
TEAM("5", "班组"),
/**
* OMS
*/
OMS("6", "OMS"),
;
@EnumValue
@JsonValue
private String code;
private String desc;
/**
* 通过value值获取枚举类型
*
* @param code code值
* @return
*/
public static WorkspaceTypeCodeEnum getByCode(String code) {
return Arrays.stream(values()).filter(l -> l.getCode().equals(code)).findFirst().orElse(null);
}
public static String getDescByCode(String code) {
return Optional.ofNullable(getByCode(code)).map(WorkspaceTypeCodeEnum::getDesc).orElse(null);
}
/**
* 后台允许新增的租户类型
*/
public static final List<WorkspaceTypeCodeEnum> ALLOW_ADD_WORKSPACE_TYPE_CODE_ENUM = Lists.newArrayList(GENERAL_ENT, GENERAL_PROJECT, CHIEF);
}

View File

@ -27,9 +27,18 @@ public class ProductSearchPageReq extends PageRequest {
*/
private Long dictWorkspaceTypeId;
/**
* 租户编码工作台编码
*/
private Long dictWorkspaceTypeCode;
/**
* 状态
*/
private Integer status;
/**
* 产品类型
*/
private String productCategory;
}

View File

@ -97,4 +97,111 @@ public class ProductVO {
*/
private List<Integer> ouTypes;
/**
* 产品类型
* PRODUCT_VERSON:产品版本类型ADD_VALUE_SERVICE:增值服务类型
* GENERAL_SERVICE:通用产品类型HARD_WARE:硬件产品类型
*/
private String category;
/**
* 产品类型名称
*/
private String productCategoryDesc;
/**
* 版本升级序列(数字越小版本越低不能降级只能升级) <企业项目产品>
*/
private Integer version;
/**
* 人数上限 <企业项目产品>
*/
private Integer maxPersonCount;
/**
* 最大项目数 <企业产品>
*/
private Integer maxWorkspaceCount;
/**
* 价格(单位)
*/
private Long price;
/**
* 产品详情
*/
private List<Sku> skus;
/**
* 素材<仅硬件产品支持>
*/
private Material material;
/**
* 功能范围(政务产品只取根节点的featureId后台取拉群所选根节点的所有子节点featureId)
*/
private FeatureScope featureScope;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Sku {
/**
* SKU名称
*/
private String skuName;
/**
* 规格型号
*/
private String model;
/**
* 数量
*/
private Integer count;
/**
* 单位
*/
private String unit;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Material {
/**
* 图片
*/
private List<String> images;
/**
* 视频
*/
private List<String> videos;
/**
* 详情大图
*/
private List<String> detailImages;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class FeatureScope {
/**
* 政务端featureResourceId
*/
private Long chiefFeatureResourceId;
}
}

View File

@ -0,0 +1,167 @@
package cn.axzo.tyr.client.model.req;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* @author likunpeng
* @version 1.0
* @date 2024/4/26
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProductSaveReq {
/**
* 产品ID
*/
private Long id;
/**
* 产品名称
*/
@NotBlank(message = "产品名称不能为空")
@Length(max = 35, message = "产品名称长度不能超过 35 个字符")
private String productName;
/**
* 产品icon
*/
@NotBlank(message = "产品icon不能为空")
private String icon;
/**
* 产品所属租户类型
*/
@NotNull(message = "租户类型不能为空")
private Long dictWorkspaceTypeId;
/**
* 产品类型
*/
@NotBlank(message = "产品类型不能为空")
private String productCategory;
/**
* 版本升级序列(数字越小版本越低不能降级只能升级) <企业项目产品>
*/
@Min(value = 0, message = "版本升级序列有误")
private Integer version;
/**
* 人数上限 <企业项目产品>
*/
@Min(value = 0, message = "人数上限有误")
private Integer maxPersonCount;
/**
* 最大项目数 <企业产品>
*/
@Min(value = 0, message = "最大项目数有误")
private Integer maxWorkspaceCount;
/**
* 价格单位 <企业项目产品>
*/
@Min(value = 0, message = "价格有误")
private Long price;
/**
* SKU列表
*/
@Valid
private List<Sku> skus;
/**
* 素材<仅硬件产品支持>
*/
private Material material;
/**
* 功能范围(政务产品只取根节点的featureId后台取拉群所选根节点的所有子节点featureId)
*/
private FeatureScope featureScope;
/**
* 操作人
*/
private Long operator;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Sku {
/**
* SKU名称
*/
@NotNull(message = "SKU名称不能为空")
private String skuName;
/**
* 规格型号
*/
@NotBlank(message = "规格型号不能为空")
private String model;
/**
* 数量
*/
@NotNull(message = "数量不能为空")
@Min(value = 1, message = "数量有误")
private Integer count;
/**
* 单位
*/
@NotBlank(message = "单位不能为空")
private String unit;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Material {
/**
* 图片素材
*/
private List<String> images;
/**
* 视频素材
*/
private List<String> videos;
/**
* 详情介绍大图
*/
private List<String> detailImages;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class FeatureScope {
/**
* 政务端featureResourceId
*/
private Long chiefFeatureResourceId;
}
}

View File

@ -0,0 +1,35 @@
package cn.axzo.tyr.client.model.req;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
/**
* @author likunpeng
* @version 1.0
* @date 2024/4/26
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UpdateProductStatusReq {
/**
* 产品ID
*/
@NotNull(message = "产品ID不能为空")
@Min(value = 1, message = "产品ID有误")
private Long id;
/**
* 状态
*/
@NotNull(message = "状态不能为空")
@Min(value = 0, message = "状态有误")
@Max(value = 1, message = "状态有误")
private Integer status;
}

View File

@ -0,0 +1,28 @@
package cn.axzo.tyr.client.model.res;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author likunpeng
* @version 1.0
* @date 2024/4/30
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ChiefTerminalResp {
/**
* 功能资源ID
*/
private Long featureResourceId;
/**
* 功能资源名称
*/
private String featureResourceName;
}

View File

@ -11,6 +11,9 @@ import cn.axzo.tyr.client.model.product.ProductSearchListReq;
import cn.axzo.tyr.client.model.product.ProductSearchPageReq;
import cn.axzo.tyr.client.model.product.ProductUpdateReq;
import cn.axzo.tyr.client.model.product.ProductVO;
import cn.axzo.tyr.client.model.req.ProductSaveReq;
import cn.axzo.tyr.client.model.req.UpdateProductStatusReq;
import cn.axzo.tyr.client.model.res.ChiefTerminalResp;
import cn.axzo.tyr.server.model.PermissionCacheKey;
import cn.axzo.tyr.server.service.PermissionCacheService;
import cn.axzo.tyr.server.service.ProductFeatureRelationService;
@ -135,4 +138,37 @@ public class ProductController implements ProductApi {
public ApiResult<Map<Long, List<ProductFeatureRelationVO>>> queryProductFeatureRelationByWorkspace(Set<Long> workspaceIds) {
return ApiResult.ok(productFeatureRelationService.getByWorkspace(workspaceIds));
}
/**
* 产品上下架
*
* @param req 产品及状态信息
* @return 返回是否更新成功
*/
@Override
public ApiResult<Void> updateStatus(UpdateProductStatusReq req) {
return productService.updateStatus(req);
}
/**
* 保存更新产品v2版本
*
* @param req 产品信息
* @return 返回产品ID
*/
@Override
public ApiResult<Long> saveOrUpdate(ProductSaveReq req) {
return productService.saveOrUpdate(req);
}
/**
* 获取政务端列表
*
* @param terminal 政务端
* @return 返回端列表
*/
@Override
public ApiResult<List<ChiefTerminalResp>> getChiefTerminal(String terminal) {
return productService.getChiefTerminal(terminal);
}
}

View File

@ -1,11 +1,11 @@
package cn.axzo.tyr.server.repository.entity;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.tyr.server.repository.handler.ProductModuleSkuHandler;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import lombok.*;
import org.apache.commons.lang3.StringUtils;
import java.io.Serializable;
@ -13,7 +13,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* saas-产品表(SaasProduct)表实体类
@ -25,7 +24,7 @@ import java.util.stream.Stream;
@Setter
@ToString
@EqualsAndHashCode(callSuper = true)
@TableName("product_module")
@TableName(value = "product_module", autoResultMap = true)
public class ProductModule extends BaseEntity<ProductModule> {
/**
@ -82,6 +81,56 @@ public class ProductModule extends BaseEntity<ProductModule> {
*/
private String ouType;
/**
* 创建人
*/
private Long createBy;
/**
* 修改人
*/
private Long updateBy;
/**
* 产品类型
* PRODUCT_VERSION:产品版本类型ADD_VALUE_SERVICE:增值服务类型
* GENERAL_SERVICE:通用产品类型HARD_WARE:硬件产品类型
*/
private String category;
/**
* 版本升级序列(数字越小版本越低不能降级只能升级) <企业项目产品>
*/
private Integer version;
/**
* 人数上限 <企业项目产品>
*/
private Integer maxPersonCount;
/**
* 最大项目数 <企业产品>
*/
private Integer maxWorkspaceCount;
/**
* 价格(单位)
*/
private Long price;
/**
* 产品详情 jsonList(skuNameSKU名称model规格型号count数量unit单位)
*/
@TableField(value = "skus", typeHandler = ProductModuleSkuHandler.class)
private List<Sku> skus;
/**
* 素材<仅硬件产品支持>json类型
* ({"miages":List<String>,"videos":List<String>,"detailImages":List<String>})
*/
@TableField(value = "material", typeHandler = FastjsonTypeHandler.class)
private Material material;
/**
* 获取主键值
*
@ -100,5 +149,54 @@ public class ProductModule extends BaseEntity<ProductModule> {
return new ArrayList<>();
}
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Sku {
/**
* SKU名称
*/
private String skuName;
/**
* 规格型号
*/
private String model;
/**
* 数量
*/
private Integer count;
/**
* 单位
*/
private String unit;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Material {
/**
* 图片
*/
private List<String> images;
/**
* 视频
*/
private List<String> videos;
/**
* 详情大图
*/
private List<String> detailImages;
}
}

View File

@ -0,0 +1,42 @@
package cn.axzo.tyr.server.repository.handler;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
/**
* @author likunpeng
* @date 2024/5/16
* @version 1.0
*/
public abstract class ListTypeHandler<T> extends BaseTypeHandler<List<T>> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List<T> parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, JSON.toJSONString(parameter));
}
@Override
public List<T> getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.wasNull() ? null : JSON.parseObject(rs.getString(columnName), specificType());
}
@Override
public List<T> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.wasNull() ? null : JSON.parseObject(rs.getString(columnIndex), specificType());
}
@Override
public List<T> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.wasNull() ? null : JSON.parseObject(cs.getString(columnIndex), specificType());
}
protected abstract TypeReference<List<T>> specificType();
}

View File

@ -0,0 +1,20 @@
package cn.axzo.tyr.server.repository.handler;
import cn.axzo.tyr.server.repository.entity.ProductModule;
import com.alibaba.fastjson.TypeReference;
import org.apache.ibatis.type.MappedTypes;
import java.util.List;
/**
* @author likunpeng
* @version 1.0
* @date 2024/5/6
*/
@MappedTypes({List.class})
public class ProductModuleSkuHandler extends ListTypeHandler<ProductModule.Sku> {
@Override
protected TypeReference<List<ProductModule.Sku>> specificType() {
return new TypeReference<List<ProductModule.Sku>>(){};
}
}

View File

@ -7,6 +7,9 @@ import cn.axzo.tyr.client.model.product.ProductSearchListReq;
import cn.axzo.tyr.client.model.product.ProductSearchPageReq;
import cn.axzo.tyr.client.model.product.ProductUpdateReq;
import cn.axzo.tyr.client.model.product.ProductVO;
import cn.axzo.tyr.client.model.req.ProductSaveReq;
import cn.axzo.tyr.client.model.req.UpdateProductStatusReq;
import cn.axzo.tyr.client.model.res.ChiefTerminalResp;
import java.util.List;
@ -29,4 +32,10 @@ public interface ProductService {
ApiResult<ProductVO> update(ProductUpdateReq req);
ApiResult<ProductVO> delete(Long id);
ApiResult<Void> updateStatus(UpdateProductStatusReq req);
ApiResult<Long> saveOrUpdate(ProductSaveReq req);
ApiResult<List<ChiefTerminalResp>> getChiefTerminal(String terminal);
}

View File

@ -51,4 +51,6 @@ public interface SaasFeatureResourceService {
Set<Long> listAuthFree();
List<SaasFeatureResource> listNavMenu(String terminal);
List<SaasFeatureResource> listByParentIdAndTerminalAndIds(Long parentId, String terminal, List<Long> featureIds);
}

View File

@ -5,23 +5,31 @@ import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.framework.domain.page.PageResp;
import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.tyr.client.model.product.ProductAddReq;
import cn.axzo.tyr.client.model.product.ProductSearchListReq;
import cn.axzo.tyr.client.model.product.ProductSearchPageReq;
import cn.axzo.tyr.client.model.product.ProductUpdateReq;
import cn.axzo.tyr.client.model.product.ProductVO;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.tyr.client.model.dict.response.BasicDictNodeResp;
import cn.axzo.tyr.client.model.enums.ProductModuleCategoryEnum;
import cn.axzo.tyr.client.model.enums.WorkspaceTypeCodeEnum;
import cn.axzo.tyr.client.model.product.*;
import cn.axzo.tyr.client.model.req.ProductSaveReq;
import cn.axzo.tyr.client.model.req.UpdateProductStatusReq;
import cn.axzo.tyr.client.model.res.ChiefTerminalResp;
import cn.axzo.tyr.server.repository.entity.ProductModule;
import cn.axzo.tyr.server.repository.dao.ProductModuleDao;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import cn.axzo.tyr.server.service.ProductFeatureRelationService;
import cn.axzo.tyr.server.service.ProductService;
import cn.hutool.core.util.StrUtil;
import cn.axzo.tyr.server.service.SaasBasicDictService;
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import io.swagger.models.auth.In;
import com.google.common.collect.Sets;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.Integers;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
@ -40,6 +48,11 @@ import java.util.stream.Collectors;
public class ProductServiceImpl implements ProductService {
private final ProductModuleDao productModuleDao;
private final ProductFeatureRelationService productFeatureRelationService;
private final SaasFeatureResourceService saasFeatureResourceService;
private final SaasBasicDictService saasBasicDictService;
// todo 政务端最终使用常量
private final static String CHIEF_TERMINAL = "NT_CHIEF";
@Override
public ApiResult<List<ProductVO>> list(ProductSearchListReq req) {
@ -76,9 +89,15 @@ public class ProductServiceImpl implements ProductService {
IPage<ProductModule> page = productModuleDao.lambdaQuery()
.like(StringUtils.hasLength(req.getName()), ProductModule::getProductName, req.getName())
.eq(Objects.nonNull(req.getDictWorkspaceTypeId()), ProductModule::getDictWorkspaceTypeId, req.getDictWorkspaceTypeId())
.eq(Objects.nonNull(req.getDictWorkspaceTypeCode()), ProductModule::getDictWorkspaceTypeCode, req.getDictWorkspaceTypeCode())
.eq(Objects.nonNull(req.getStatus()), ProductModule::getStatus, req.getStatus())
.eq(org.apache.commons.lang3.StringUtils.isNotBlank(req.getProductCategory()), ProductModule::getCategory, req.getProductCategory())
.page(req.toPage());
List<ProductVO> list = BeanMapper.copyList(page.getRecords(), ProductVO.class);
list.forEach(e -> {
e.setProductCategoryDesc(ProductModuleCategoryEnum.getDescByCode(e.getCategory()));
e.setDictWorkspaceTypeDesc(WorkspaceTypeCodeEnum.getDescByCode(e.getDictWorkspaceTypeCode()));
});
PageResp<ProductVO> data = PageResp.list(page.getCurrent(), page.getSize(), page.getTotal(), list);
return ApiPageResult.ok(data);
}
@ -88,6 +107,23 @@ public class ProductServiceImpl implements ProductService {
ProductModule byId = productModuleDao.getById(id);
ProductVO productVO = BeanMapper.copyBean(byId, ProductVO.class);
productVO.setOuTypes(byId.parseOuType());
productVO.setProductCategoryDesc(ProductModuleCategoryEnum.getDescByCode(productVO.getCategory()));
productVO.setDictWorkspaceTypeDesc(WorkspaceTypeCodeEnum.getDescByCode(productVO.getDictWorkspaceTypeCode()));
productVO.setSkus(org.apache.commons.collections.CollectionUtils.isEmpty(byId.getSkus()) ? Collections.emptyList()
: byId.getSkus().stream().map(e -> ProductVO.Sku.builder()
.skuName(e.getSkuName())
.model(e.getModel())
.count(e.getCount())
.unit(e.getUnit())
.build()).collect(Collectors.toList()));
productVO.setMaterial(Objects.isNull(byId.getMaterial()) ? null : ProductVO.Material.builder()
.images(byId.getMaterial().getImages())
.videos(byId.getMaterial().getVideos())
.detailImages(byId.getMaterial().getDetailImages())
.build());
if (WorkspaceTypeCodeEnum.CHIEF.getCode().equals(productVO.getDictWorkspaceTypeCode())) {
fillFeatureScope(productVO);
}
return ApiResult.ok(productVO);
}
@ -137,4 +173,142 @@ public class ProductServiceImpl implements ProductService {
productFeatureRelationService.removeByProductId(id);
return ApiResult.ok(BeanMapper.copyBean(productModule, ProductVO.class));
}
@Override
public ApiResult<Void> updateStatus(UpdateProductStatusReq req) {
ProductModule productModule = productModuleDao.getOne(new LambdaQueryWrapper<ProductModule>()
.eq(BaseEntity::getId, req.getId())
.eq(BaseEntity::getIsDelete, Boolean.FALSE)
.last("LIMIT 1"));
AssertUtil.notNull(productModule, "产品不存在");
productModuleDao.lambdaUpdate()
.eq(ProductModule::getId, req.getId())
.set(ProductModule::getStatus, req.getStatus())
.update();
return ApiResult.ok();
}
@Override
@Transactional(rollbackFor = Exception.class)
public ApiResult<Long> saveOrUpdate(ProductSaveReq req) {
ProductModule productModule = new ProductModule();
if (Objects.nonNull(req.getId())) {
productModule = productModuleDao.getOne(new LambdaQueryWrapper<ProductModule>()
.eq(BaseEntity::getId, req.getId())
.eq(BaseEntity::getIsDelete, Boolean.FALSE)
.last("LIMIT 1"));
AssertUtil.notNull(productModule, "产品不存在");
if (Objects.nonNull(req.getVersion()) && Objects.nonNull(productModule.getVersion())) {
AssertUtil.isTrue(req.getVersion() >= productModule.getVersion(), "版本升级序列不允许降级");
}
}
validAndFillEntity(req, productModule);
if (Objects.nonNull(req.getId())) {
productModule.setUpdateBy(req.getOperator());
productModuleDao.updateById(productModule);
} else {
productModule.setCreateBy(req.getOperator());
productModuleDao.save(productModule);
}
// 保存商品权限信息
if (WorkspaceTypeCodeEnum.CHIEF.getCode().equals(productModule.getDictWorkspaceTypeCode())) {
saveChiefFeatureResource(productModule.getId(), productModule.getDictWorkspaceTypeId(), productModule.getDictWorkspaceTypeCode(), req.getFeatureScope().getChiefFeatureResourceId());
}
return ApiResult.ok(productModule.getId());
}
@Override
public ApiResult<List<ChiefTerminalResp>> getChiefTerminal(String terminal) {
List<SaasFeatureResource> featureResources = saasFeatureResourceService.listByParentIdAndTerminalAndIds(0L, terminal, null);
List<ChiefTerminalResp> resps = CollectionUtil.isEmpty(featureResources) ? Collections.emptyList() : featureResources.stream().map(e -> ChiefTerminalResp.builder()
.featureResourceId(e.getId())
.featureResourceName(e.getFeatureName())
.build()).collect(Collectors.toList());
return ApiResult.ok(resps);
}
private void validAndFillEntity(ProductSaveReq req, ProductModule productModule) {
BasicDictNodeResp basicDictNodeResp = saasBasicDictService.getById(req.getDictWorkspaceTypeId());
AssertUtil.notNull(basicDictNodeResp, "租户类型有误");
WorkspaceTypeCodeEnum workspaceTypeCodeEnum = WorkspaceTypeCodeEnum.getByCode(basicDictNodeResp.getCode());
AssertUtil.notNull(workspaceTypeCodeEnum, "租户类型有误");
AssertUtil.isTrue(WorkspaceTypeCodeEnum.ALLOW_ADD_WORKSPACE_TYPE_CODE_ENUM.contains(workspaceTypeCodeEnum), "租户类型选择有误");
// TODO 一期不允许创建企业项目租户的产品
AssertUtil.isFalse(WorkspaceTypeCodeEnum.GENERAL_ENT.equals(workspaceTypeCodeEnum) || WorkspaceTypeCodeEnum.GENERAL_PROJECT.equals(workspaceTypeCodeEnum), "企业、项目租户请在老页面创建产品");
ProductModuleCategoryEnum productModuleCategoryEnum = ProductModuleCategoryEnum.getByCode(req.getProductCategory());
AssertUtil.notNull(productModuleCategoryEnum, "产品类型有误");
if (WorkspaceTypeCodeEnum.GENERAL_ENT.equals(workspaceTypeCodeEnum) || WorkspaceTypeCodeEnum.GENERAL_PROJECT.equals(workspaceTypeCodeEnum)) {
AssertUtil.notNull(req.getVersion(), "版本升级序列不能为空");
AssertUtil.notNull(req.getMaxPersonCount(), "人数上限不能为空");
AssertUtil.notNull(req.getPrice(), "价格不能为空");
}
if (WorkspaceTypeCodeEnum.CHIEF.equals(workspaceTypeCodeEnum)) {
AssertUtil.isTrue(Objects.nonNull(req.getFeatureScope()) && Objects.nonNull(req.getFeatureScope().getChiefFeatureResourceId())
&& req.getFeatureScope().getChiefFeatureResourceId() > 0, "功能范围选择有误");
}
productModule.setProductName(req.getProductName());
productModule.setIcon(req.getIcon());
productModule.setDictWorkspaceTypeId(req.getDictWorkspaceTypeId());
productModule.setDictWorkspaceTypeCode(workspaceTypeCodeEnum.getCode());
productModule.setProductType(0);
productModule.setStatus(0);
productModule.setCategory(req.getProductCategory());
productModule.setVersion(req.getVersion());
productModule.setMaxPersonCount(req.getMaxPersonCount());
productModule.setMaxWorkspaceCount(req.getMaxWorkspaceCount());
productModule.setPrice(req.getPrice());
productModule.setSkus(org.apache.commons.collections.CollectionUtils.isEmpty(req.getSkus()) ? Lists.newArrayList()
: req.getSkus().stream().map(e -> ProductModule.Sku.builder()
.skuName(e.getSkuName())
.model(e.getModel())
.count(e.getCount())
.unit(e.getUnit())
.build()).collect(Collectors.toList()));
productModule.setMaterial(Optional.ofNullable(req.getMaterial()).map(e -> ProductModule.Material.builder()
.images(e.getImages())
.videos(e.getVideos())
.detailImages(e.getDetailImages())
.build()).orElse(ProductModule.Material.builder().build()));
}
/**
* 保存政务端产品功能权限
*/
private void saveChiefFeatureResource(Long productId, Long dictWorkspaceTypeId, String dictWorkspaceTypeCode, Long rootFeatureId) {
SaasFeatureResource saasFeatureResource = saasFeatureResourceService.featureResourceById(rootFeatureId);
AssertUtil.notNull(saasFeatureResource, "功能范围选择端不能为空");
AssertUtil.isTrue(saasFeatureResource.getParentId() == 0 && CHIEF_TERMINAL.equals(saasFeatureResource.getTerminal()), "功能范围选择端有误");
List<SaasFeatureResource> saasFeatureResources = saasFeatureResourceService.listDescendant(rootFeatureId);
ProductFeatureRelationUpdateReq req = new ProductFeatureRelationUpdateReq();
req.setDictCodeId(dictWorkspaceTypeId);
req.setDictCode(dictWorkspaceTypeCode);
req.setProductModuleId(productId);
req.setProductModuleId(productId);
Set<Long> featureIds = org.apache.commons.collections.CollectionUtils.isEmpty(saasFeatureResources) ? Sets.newHashSet()
: saasFeatureResources.stream().map(BaseEntity::getId).collect(Collectors.toSet());
featureIds.add(saasFeatureResource.getId());
req.getFeatureIds().addAll(featureIds);
productFeatureRelationService.updateFeatureRelation(Collections.singletonList(req));
}
private void fillFeatureScope(ProductVO product) {
ProductFeatureRelationSearchReq req = new ProductFeatureRelationSearchReq();
req.setProductModuleId(product.getId());
req.setDictCodeId(product.getDictWorkspaceTypeId());
req.setDictCode(product.getDictWorkspaceTypeCode());
ApiResult<List<ProductFeatureRelationVO>> result = productFeatureRelationService.featureList(req);
if (org.apache.commons.collections.CollectionUtils.isEmpty(result.getData())) {
return;
}
List<Long> featureIds = result.getData().stream().map(ProductFeatureRelationVO::getFeatureId).collect(Collectors.toList());
List<SaasFeatureResource> featureResources = saasFeatureResourceService.listByParentIdAndTerminalAndIds(0L, CHIEF_TERMINAL, featureIds);
if (CollectionUtil.isNotEmpty(featureResources)) {
product.setFeatureScope(ProductVO.FeatureScope.builder().chiefFeatureResourceId(featureResources.get(0).getId()).build());
}
}
}

View File

@ -479,4 +479,14 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic
.orderByAsc(SaasFeatureResource::getDisplayOrder)
.list();
}
@Override
public List<SaasFeatureResource> listByParentIdAndTerminalAndIds(Long parentId, String terminal, List<Long> featureIds) {
return featureResourceDao.lambdaQuery()
.eq(BaseEntity::getIsDelete, 0)
.eq(Objects.nonNull(parentId), SaasFeatureResource::getParentId, parentId)
.eq(StringUtils.isNotBlank(terminal), SaasFeatureResource::getTerminal, terminal)
.in(CollectionUtil.isNotEmpty(featureIds), SaasFeatureResource::getId, featureIds)
.list();
}
}